Move core fundamental components into bootstrap (#105560)
Co-authored-by: Erik <erik@montnemery.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
31ef034c3f
commit
80207835d7
5 changed files with 80 additions and 40 deletions
|
@ -39,7 +39,6 @@ from .helpers import (
|
||||||
from .helpers.dispatcher import async_dispatcher_send
|
from .helpers.dispatcher import async_dispatcher_send
|
||||||
from .helpers.typing import ConfigType
|
from .helpers.typing import ConfigType
|
||||||
from .setup import (
|
from .setup import (
|
||||||
DATA_SETUP,
|
|
||||||
DATA_SETUP_STARTED,
|
DATA_SETUP_STARTED,
|
||||||
DATA_SETUP_TIME,
|
DATA_SETUP_TIME,
|
||||||
async_notify_setup_error,
|
async_notify_setup_error,
|
||||||
|
@ -106,6 +105,52 @@ STAGE_1_INTEGRATIONS = {
|
||||||
# Ensure supervisor is available
|
# Ensure supervisor is available
|
||||||
"hassio",
|
"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(
|
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")
|
_LOGGER.warning("Unable to set up core integrations. Activating recovery mode")
|
||||||
recovery_mode = True
|
recovery_mode = True
|
||||||
|
|
||||||
elif (
|
elif any(domain not in hass.config.components for domain in CRITICAL_INTEGRATIONS):
|
||||||
"frontend" in hass.data.get(DATA_SETUP, {})
|
_LOGGER.warning(
|
||||||
and "frontend" not in hass.config.components
|
"Detected that %s did not load. Activating recovery mode",
|
||||||
):
|
",".join(CRITICAL_INTEGRATIONS),
|
||||||
_LOGGER.warning("Detected that frontend did not load. Activating recovery mode")
|
)
|
||||||
# Ask integrations to shut down. It's messy but we can't
|
# Ask integrations to shut down. It's messy but we can't
|
||||||
# do a clean stop without knowing what is broken
|
# do a clean stop without knowing what is broken
|
||||||
with contextlib.suppress(asyncio.TimeoutError):
|
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
|
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:
|
if not hass.config.recovery_mode:
|
||||||
|
domains.update(DEFAULT_INTEGRATIONS)
|
||||||
domains.update(hass.config_entries.async_domains())
|
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:
|
if "SUPERVISOR" in os.environ:
|
||||||
domains.add("hassio")
|
domains.update(DEFAULT_INTEGRATIONS_SUPERVISOR)
|
||||||
|
else:
|
||||||
|
domains.update(DEFAULT_INTEGRATIONS_NON_SUPERVISOR)
|
||||||
|
|
||||||
return domains
|
return domains
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
"""Component providing default configuration for new users."""
|
"""Component providing default configuration for new users."""
|
||||||
from homeassistant.components.hassio import is_hassio
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.setup import async_setup_component
|
|
||||||
|
|
||||||
DOMAIN = "default_config"
|
DOMAIN = "default_config"
|
||||||
|
|
||||||
|
@ -12,7 +10,4 @@ CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
"""Initialize default configuration."""
|
"""Initialize default configuration."""
|
||||||
if not is_hassio(hass):
|
|
||||||
await async_setup_component(hass, "backup", config)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -3,46 +3,25 @@
|
||||||
"name": "Default Config",
|
"name": "Default Config",
|
||||||
"codeowners": ["@home-assistant/core"],
|
"codeowners": ["@home-assistant/core"],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"application_credentials",
|
|
||||||
"assist_pipeline",
|
"assist_pipeline",
|
||||||
"automation",
|
|
||||||
"bluetooth",
|
"bluetooth",
|
||||||
"cloud",
|
"cloud",
|
||||||
"conversation",
|
"conversation",
|
||||||
"counter",
|
|
||||||
"dhcp",
|
"dhcp",
|
||||||
"energy",
|
"energy",
|
||||||
"frontend",
|
|
||||||
"hardware",
|
|
||||||
"history",
|
"history",
|
||||||
"homeassistant_alerts",
|
"homeassistant_alerts",
|
||||||
"input_boolean",
|
|
||||||
"input_button",
|
|
||||||
"input_datetime",
|
|
||||||
"input_number",
|
|
||||||
"input_select",
|
|
||||||
"input_text",
|
|
||||||
"logbook",
|
"logbook",
|
||||||
"logger",
|
|
||||||
"map",
|
"map",
|
||||||
"media_source",
|
"media_source",
|
||||||
"mobile_app",
|
"mobile_app",
|
||||||
"my",
|
"my",
|
||||||
"network",
|
|
||||||
"person",
|
|
||||||
"scene",
|
|
||||||
"schedule",
|
|
||||||
"script",
|
|
||||||
"ssdp",
|
"ssdp",
|
||||||
"stream",
|
"stream",
|
||||||
"sun",
|
"sun",
|
||||||
"system_health",
|
|
||||||
"tag",
|
|
||||||
"timer",
|
|
||||||
"usb",
|
"usb",
|
||||||
"webhook",
|
"webhook",
|
||||||
"zeroconf",
|
"zeroconf"
|
||||||
"zone"
|
|
||||||
],
|
],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/default_config",
|
"documentation": "https://www.home-assistant.io/integrations/default_config",
|
||||||
"integration_type": "system",
|
"integration_type": "system",
|
||||||
|
|
|
@ -3,6 +3,7 @@ from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant import bootstrap
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import recorder as recorder_helper
|
from homeassistant.helpers import recorder as recorder_helper
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
@ -34,4 +35,9 @@ async def test_setup(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test setup."""
|
"""Test setup."""
|
||||||
recorder_helper.async_initialize_recorder(hass)
|
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"})
|
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:
|
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):
|
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"}):
|
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])
|
@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])
|
@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(
|
async def test_empty_integrations_list_is_only_sent_at_the_end_of_bootstrap(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -836,7 +846,7 @@ async def test_empty_integrations_list_is_only_sent_at_the_end_of_bootstrap(
|
||||||
|
|
||||||
assert integrations[0] != {}
|
assert integrations[0] != {}
|
||||||
assert "an_after_dep" in integrations[0]
|
assert "an_after_dep" in integrations[0]
|
||||||
assert integrations[-3] != {}
|
assert integrations[-2] != {}
|
||||||
assert integrations[-1] == {}
|
assert integrations[-1] == {}
|
||||||
|
|
||||||
assert "normal_integration" in hass.config.components
|
assert "normal_integration" in hass.config.components
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue