mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 01:21:51 +02:00
Add container arch to system info (#147372)
This commit is contained in:
@ -12,7 +12,6 @@ import re
|
||||
import struct
|
||||
from typing import Any, NamedTuple
|
||||
|
||||
import aiofiles
|
||||
from aiohasupervisor import SupervisorError
|
||||
import voluptuous as vol
|
||||
|
||||
@ -239,12 +238,6 @@ def _is_32_bit() -> bool:
|
||||
return size * 8 == 32
|
||||
|
||||
|
||||
async def _get_arch() -> str:
|
||||
async with aiofiles.open("/etc/apk/arch") as arch_file:
|
||||
raw_arch = await arch_file.read()
|
||||
return {"x86": "i386"}.get(raw_arch, raw_arch)
|
||||
|
||||
|
||||
class APIEndpointSettings(NamedTuple):
|
||||
"""Settings for API endpoint."""
|
||||
|
||||
@ -566,8 +559,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
hass.data[ADDONS_COORDINATOR] = coordinator
|
||||
|
||||
arch = await _get_arch()
|
||||
|
||||
def deprecated_setup_issue() -> None:
|
||||
os_info = get_os_info(hass)
|
||||
info = get_info(hass)
|
||||
@ -575,6 +566,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
return
|
||||
is_haos = info.get("hassos") is not None
|
||||
board = os_info.get("board")
|
||||
arch = info.get("arch", "unknown")
|
||||
unsupported_board = board in {"tinker", "odroid-xu4", "rpi2"}
|
||||
unsupported_os_on_board = board in {"rpi3", "rpi4"}
|
||||
if is_haos and (unsupported_board or unsupported_os_on_board):
|
||||
|
@ -7,7 +7,6 @@ import logging
|
||||
import struct
|
||||
from typing import Any
|
||||
|
||||
import aiofiles
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config as conf_util, core_config
|
||||
@ -18,6 +17,7 @@ from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_LATITUDE,
|
||||
ATTR_LONGITUDE,
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
RESTART_EXIT_CODE,
|
||||
SERVICE_RELOAD,
|
||||
SERVICE_SAVE_PERSISTENT_STATES,
|
||||
@ -26,6 +26,7 @@ from homeassistant.const import (
|
||||
SERVICE_TURN_ON,
|
||||
)
|
||||
from homeassistant.core import (
|
||||
Event,
|
||||
HomeAssistant,
|
||||
ServiceCall,
|
||||
ServiceResponse,
|
||||
@ -101,12 +102,6 @@ def _is_32_bit() -> bool:
|
||||
return size * 8 == 32
|
||||
|
||||
|
||||
async def _get_arch() -> str:
|
||||
async with aiofiles.open("/etc/apk/arch") as arch_file:
|
||||
raw_arch = (await arch_file.read()).strip()
|
||||
return {"x86": "i386", "x86_64": "amd64"}.get(raw_arch, raw_arch)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa: C901
|
||||
"""Set up general services related to Home Assistant."""
|
||||
|
||||
@ -411,45 +406,50 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
||||
hass.data[DATA_EXPOSED_ENTITIES] = exposed_entities
|
||||
async_set_stop_handler(hass, _async_stop)
|
||||
|
||||
info = await async_get_system_info(hass)
|
||||
async def _async_check_deprecation(event: Event) -> None:
|
||||
"""Check and create deprecation issues after startup."""
|
||||
info = await async_get_system_info(hass)
|
||||
|
||||
installation_type = info["installation_type"][15:]
|
||||
if installation_type in {"Core", "Container"}:
|
||||
deprecated_method = installation_type == "Core"
|
||||
bit32 = _is_32_bit()
|
||||
arch = info["arch"]
|
||||
if bit32 and installation_type == "Container":
|
||||
arch = await _get_arch()
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"deprecated_container",
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_container",
|
||||
translation_placeholders={"arch": arch},
|
||||
)
|
||||
deprecated_architecture = bit32 and installation_type != "Container"
|
||||
if deprecated_method or deprecated_architecture:
|
||||
issue_id = "deprecated"
|
||||
if deprecated_method:
|
||||
issue_id += "_method"
|
||||
if deprecated_architecture:
|
||||
issue_id += "_architecture"
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
issue_id,
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key=issue_id,
|
||||
translation_placeholders={
|
||||
"installation_type": installation_type,
|
||||
"arch": arch,
|
||||
},
|
||||
)
|
||||
installation_type = info["installation_type"][15:]
|
||||
if installation_type in {"Core", "Container"}:
|
||||
deprecated_method = installation_type == "Core"
|
||||
bit32 = _is_32_bit()
|
||||
arch = info["arch"]
|
||||
if bit32 and installation_type == "Container":
|
||||
arch = info.get("container_arch", arch)
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"deprecated_container",
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_container",
|
||||
translation_placeholders={"arch": arch},
|
||||
)
|
||||
deprecated_architecture = bit32 and installation_type != "Container"
|
||||
if deprecated_method or deprecated_architecture:
|
||||
issue_id = "deprecated"
|
||||
if deprecated_method:
|
||||
issue_id += "_method"
|
||||
if deprecated_architecture:
|
||||
issue_id += "_architecture"
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
issue_id,
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key=issue_id,
|
||||
translation_placeholders={
|
||||
"installation_type": installation_type,
|
||||
"arch": arch,
|
||||
},
|
||||
)
|
||||
|
||||
# Delay deprecation check to make sure installation method is determined correctly
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _async_check_deprecation)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -124,6 +124,7 @@
|
||||
"info": {
|
||||
"arch": "CPU architecture",
|
||||
"config_dir": "Configuration directory",
|
||||
"container_arch": "Container architecture",
|
||||
"dev": "Development",
|
||||
"docker": "Docker",
|
||||
"hassio": "Supervisor",
|
||||
|
@ -27,6 +27,7 @@ async def system_health_info(hass: HomeAssistant) -> dict[str, Any]:
|
||||
"dev": info.get("dev"),
|
||||
"hassio": info.get("hassio"),
|
||||
"docker": info.get("docker"),
|
||||
"container_arch": info.get("container_arch"),
|
||||
"user": info.get("user"),
|
||||
"virtualenv": info.get("virtualenv"),
|
||||
"python_version": info.get("python_version"),
|
||||
|
@ -21,6 +21,7 @@ from .singleton import singleton
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
_DATA_MAC_VER = "system_info_mac_ver"
|
||||
_DATA_CONTAINER_ARCH = "system_info_container_arch"
|
||||
|
||||
|
||||
@singleton(_DATA_MAC_VER)
|
||||
@ -29,6 +30,22 @@ async def async_get_mac_ver(hass: HomeAssistant) -> str:
|
||||
return (await hass.async_add_executor_job(platform.mac_ver))[0]
|
||||
|
||||
|
||||
@singleton(_DATA_CONTAINER_ARCH)
|
||||
async def async_get_container_arch(hass: HomeAssistant) -> str:
|
||||
"""Return the container architecture."""
|
||||
|
||||
def _read_arch_file() -> str:
|
||||
"""Read the architecture from /etc/apk/arch."""
|
||||
with open("/etc/apk/arch", encoding="utf-8") as arch_file:
|
||||
return arch_file.read().strip()
|
||||
|
||||
try:
|
||||
raw_arch = await hass.async_add_executor_job(_read_arch_file)
|
||||
except FileNotFoundError:
|
||||
return "unknown"
|
||||
return {"x86": "i386", "x86_64": "amd64"}.get(raw_arch, raw_arch)
|
||||
|
||||
|
||||
# Cache the result of getuser() because it can call getpwuid() which
|
||||
# can do blocking I/O to look up the username in /etc/passwd.
|
||||
cached_get_user = cache(getuser)
|
||||
@ -79,6 +96,7 @@ async def async_get_system_info(hass: HomeAssistant) -> dict[str, Any]:
|
||||
if info_object["docker"]:
|
||||
if info_object["user"] == "root" and is_official_image():
|
||||
info_object["installation_type"] = "Home Assistant Container"
|
||||
info_object["container_arch"] = await async_get_container_arch(hass)
|
||||
else:
|
||||
info_object["installation_type"] = "Unsupported Third Party Container"
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
aiodhcpwatcher==1.2.0
|
||||
aiodiscover==2.7.0
|
||||
aiodns==3.5.0
|
||||
aiofiles==24.1.0
|
||||
aiohasupervisor==0.3.1
|
||||
aiohttp-asyncmdnsresolver==0.1.1
|
||||
aiohttp-fast-zlib==0.3.0
|
||||
@ -201,6 +200,14 @@ tenacity!=8.4.0
|
||||
# TypeError: 'Timeout' object does not support the context manager protocol
|
||||
async-timeout==4.0.3
|
||||
|
||||
# aiofiles keeps getting downgraded by custom components
|
||||
# causing newer methods to not be available and breaking
|
||||
# some integrations at startup
|
||||
# https://github.com/home-assistant/core/issues/127529
|
||||
# https://github.com/home-assistant/core/issues/122508
|
||||
# https://github.com/home-assistant/core/issues/118004
|
||||
aiofiles>=24.1.0
|
||||
|
||||
# multidict < 6.4.0 has memory leaks
|
||||
# https://github.com/aio-libs/multidict/issues/1134
|
||||
# https://github.com/aio-libs/multidict/issues/1131
|
||||
|
@ -24,7 +24,6 @@ classifiers = [
|
||||
requires-python = ">=3.13.2"
|
||||
dependencies = [
|
||||
"aiodns==3.5.0",
|
||||
"aiofiles==24.1.0",
|
||||
# Integrations may depend on hassio integration without listing it to
|
||||
# change behavior based on presence of supervisor. Deprecated with #127228
|
||||
# Lib can be removed with 2025.11
|
||||
|
1
requirements.txt
generated
1
requirements.txt
generated
@ -4,7 +4,6 @@
|
||||
|
||||
# Home Assistant Core
|
||||
aiodns==3.5.0
|
||||
aiofiles==24.1.0
|
||||
aiohasupervisor==0.3.1
|
||||
aiohttp==3.12.13
|
||||
aiohttp_cors==0.8.1
|
||||
|
@ -226,6 +226,14 @@ tenacity!=8.4.0
|
||||
# TypeError: 'Timeout' object does not support the context manager protocol
|
||||
async-timeout==4.0.3
|
||||
|
||||
# aiofiles keeps getting downgraded by custom components
|
||||
# causing newer methods to not be available and breaking
|
||||
# some integrations at startup
|
||||
# https://github.com/home-assistant/core/issues/127529
|
||||
# https://github.com/home-assistant/core/issues/122508
|
||||
# https://github.com/home-assistant/core/issues/118004
|
||||
aiofiles>=24.1.0
|
||||
|
||||
# multidict < 6.4.0 has memory leaks
|
||||
# https://github.com/aio-libs/multidict/issues/1134
|
||||
# https://github.com/aio-libs/multidict/issues/1131
|
||||
|
@ -9,6 +9,7 @@
|
||||
dev | False
|
||||
hassio | False
|
||||
docker | False
|
||||
container_arch | None
|
||||
user | hass
|
||||
virtualenv | False
|
||||
python_version | 3.13.1
|
||||
|
@ -1931,6 +1931,7 @@ async def test_download_support_package(
|
||||
"virtualenv": False,
|
||||
"python_version": "3.13.1",
|
||||
"docker": False,
|
||||
"container_arch": None,
|
||||
"arch": "x86_64",
|
||||
"timezone": "US/Pacific",
|
||||
"os_name": "Linux",
|
||||
|
@ -260,16 +260,3 @@ def all_setup_requests(
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def arch() -> str:
|
||||
"""Arch found in apk file."""
|
||||
return "amd64"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_arch_file(arch: str) -> Generator[None]:
|
||||
"""Mock arch file."""
|
||||
with patch("homeassistant.components.hassio._get_arch", return_value=arch):
|
||||
yield
|
||||
|
@ -1156,10 +1156,6 @@ def test_deprecated_constants(
|
||||
("rpi2", "deprecated_os_armv7"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"arch",
|
||||
["armv7"],
|
||||
)
|
||||
async def test_deprecated_installation_issue_os_armv7(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
@ -1170,13 +1166,6 @@ async def test_deprecated_installation_issue_os_armv7(
|
||||
"""Test deprecated installation issue."""
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": "armv7",
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=True,
|
||||
@ -1185,7 +1174,8 @@ async def test_deprecated_installation_issue_os_armv7(
|
||||
"homeassistant.components.hassio.get_os_info", return_value={"board": board}
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_info", return_value={"hassos": True}
|
||||
"homeassistant.components.hassio.get_info",
|
||||
return_value={"hassos": True, "arch": "armv7"},
|
||||
),
|
||||
patch("homeassistant.components.hardware.async_setup", return_value=True),
|
||||
):
|
||||
@ -1238,13 +1228,6 @@ async def test_deprecated_installation_issue_32bit_os(
|
||||
"""Test deprecated architecture issue."""
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=True,
|
||||
@ -1254,7 +1237,8 @@ async def test_deprecated_installation_issue_32bit_os(
|
||||
return_value={"board": "rpi3-64"},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_info", return_value={"hassos": True}
|
||||
"homeassistant.components.hassio.get_info",
|
||||
return_value={"hassos": True, "arch": arch},
|
||||
),
|
||||
patch("homeassistant.components.hardware.async_setup", return_value=True),
|
||||
):
|
||||
@ -1305,13 +1289,6 @@ async def test_deprecated_installation_issue_32bit_supervised(
|
||||
"""Test deprecated architecture issue."""
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Supervised",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=True,
|
||||
@ -1321,7 +1298,8 @@ async def test_deprecated_installation_issue_32bit_supervised(
|
||||
return_value={"board": "rpi3-64"},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_info", return_value={"hassos": None}
|
||||
"homeassistant.components.hassio.get_info",
|
||||
return_value={"hassos": None, "arch": arch},
|
||||
),
|
||||
patch("homeassistant.components.hardware.async_setup", return_value=True),
|
||||
):
|
||||
@ -1376,13 +1354,6 @@ async def test_deprecated_installation_issue_64bit_supervised(
|
||||
"""Test deprecated architecture issue."""
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Supervised",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=False,
|
||||
@ -1392,7 +1363,8 @@ async def test_deprecated_installation_issue_64bit_supervised(
|
||||
return_value={"board": "generic-x86-64"},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_info", return_value={"hassos": None}
|
||||
"homeassistant.components.hassio.get_info",
|
||||
return_value={"hassos": None, "arch": arch},
|
||||
),
|
||||
patch("homeassistant.components.hardware.async_setup", return_value=True),
|
||||
):
|
||||
@ -1445,13 +1417,6 @@ async def test_deprecated_installation_issue_supported_board(
|
||||
"""Test no deprecated installation issue for a supported board."""
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": "aarch64",
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=False,
|
||||
@ -1460,7 +1425,8 @@ async def test_deprecated_installation_issue_supported_board(
|
||||
"homeassistant.components.hassio.get_os_info", return_value={"board": board}
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_info", return_value={"hassos": True}
|
||||
"homeassistant.components.hassio.get_info",
|
||||
return_value={"hassos": True, "arch": "aarch64"},
|
||||
),
|
||||
):
|
||||
assert await async_setup_component(hass, "homeassistant", {})
|
||||
|
@ -24,6 +24,7 @@ from homeassistant.const import (
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
EVENT_CORE_CONFIG_UPDATE,
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
SERVICE_SAVE_PERSISTENT_STATES,
|
||||
SERVICE_TOGGLE,
|
||||
SERVICE_TURN_OFF,
|
||||
@ -668,6 +669,7 @@ async def test_deprecated_installation_issue_32bit_core(
|
||||
),
|
||||
):
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
@ -707,6 +709,7 @@ async def test_deprecated_installation_issue_64bit_core(
|
||||
),
|
||||
):
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
@ -738,6 +741,7 @@ async def test_deprecated_installation_issue_32bit(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Container",
|
||||
"container_arch": arch,
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
@ -745,12 +749,9 @@ async def test_deprecated_installation_issue_32bit(
|
||||
"homeassistant.components.homeassistant._is_32_bit",
|
||||
return_value=True,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant._get_arch",
|
||||
return_value=arch,
|
||||
),
|
||||
):
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
|
Reference in New Issue
Block a user