mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 01:21:51 +02:00
Make issue creation check architecture instead of uname (#146537)
This commit is contained in:
committed by
Franck Nijhof
parent
60b8230ecc
commit
02524b8b9b
@ -9,8 +9,10 @@ from functools import partial
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
from typing import Any, NamedTuple
|
||||
|
||||
import aiofiles
|
||||
from aiohasupervisor import SupervisorError
|
||||
import voluptuous as vol
|
||||
|
||||
@ -56,7 +58,6 @@ from homeassistant.helpers.issue_registry import IssueSeverity
|
||||
from homeassistant.helpers.service_info.hassio import (
|
||||
HassioServiceInfo as _HassioServiceInfo,
|
||||
)
|
||||
from homeassistant.helpers.system_info import async_get_system_info
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.util.async_ import create_eager_task
|
||||
@ -233,6 +234,17 @@ SCHEMA_RESTORE_PARTIAL = SCHEMA_RESTORE_FULL.extend(
|
||||
)
|
||||
|
||||
|
||||
def _is_32_bit() -> bool:
|
||||
size = struct.calcsize("P")
|
||||
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."""
|
||||
|
||||
@ -554,7 +566,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
hass.data[ADDONS_COORDINATOR] = coordinator
|
||||
|
||||
system_info = await async_get_system_info(hass)
|
||||
arch = await _get_arch()
|
||||
|
||||
def deprecated_setup_issue() -> None:
|
||||
os_info = get_os_info(hass)
|
||||
@ -562,20 +574,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
if os_info is None or info is None:
|
||||
return
|
||||
is_haos = info.get("hassos") is not None
|
||||
arch = system_info["arch"]
|
||||
board = os_info.get("board")
|
||||
supported_board = board in {"rpi3", "rpi4", "tinker", "odroid-xu4", "rpi2"}
|
||||
if is_haos and arch == "armv7" and supported_board:
|
||||
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):
|
||||
issue_id = "deprecated_os_"
|
||||
if board in {"rpi3", "rpi4"}:
|
||||
if unsupported_os_on_board:
|
||||
issue_id += "aarch64"
|
||||
elif board in {"tinker", "odroid-xu4", "rpi2"}:
|
||||
elif unsupported_board:
|
||||
issue_id += "armv7"
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
"homeassistant",
|
||||
issue_id,
|
||||
breaks_in_ha_version="2025.12.0",
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
@ -584,9 +595,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"installation_guide": "https://www.home-assistant.io/installation/",
|
||||
},
|
||||
)
|
||||
deprecated_architecture = False
|
||||
if arch in {"i386", "armhf"} or (arch == "armv7" and not supported_board):
|
||||
deprecated_architecture = True
|
||||
bit32 = _is_32_bit()
|
||||
deprecated_architecture = bit32 and not (
|
||||
unsupported_board or unsupported_os_on_board
|
||||
)
|
||||
if not is_haos or deprecated_architecture:
|
||||
issue_id = "deprecated"
|
||||
if not is_haos:
|
||||
@ -597,7 +609,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
hass,
|
||||
"homeassistant",
|
||||
issue_id,
|
||||
breaks_in_ha_version="2025.12.0",
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
|
@ -4,8 +4,10 @@ import asyncio
|
||||
from collections.abc import Callable, Coroutine
|
||||
import itertools as it
|
||||
import logging
|
||||
import struct
|
||||
from typing import Any
|
||||
|
||||
import aiofiles
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config as conf_util, core_config
|
||||
@ -94,6 +96,17 @@ DEPRECATION_URL = (
|
||||
)
|
||||
|
||||
|
||||
def _is_32_bit() -> bool:
|
||||
size = struct.calcsize("P")
|
||||
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."""
|
||||
|
||||
@ -403,23 +416,21 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
||||
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 arch == "armv7" and installation_type == "Container":
|
||||
if bit32 and installation_type == "Container":
|
||||
arch = await _get_arch()
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"deprecated_container_armv7",
|
||||
breaks_in_ha_version="2025.12.0",
|
||||
"deprecated_container",
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_container_armv7",
|
||||
translation_key="deprecated_container",
|
||||
translation_placeholders={"arch": arch},
|
||||
)
|
||||
deprecated_architecture = False
|
||||
if arch in {"i386", "armhf"} or (
|
||||
arch == "armv7" and installation_type != "Container"
|
||||
):
|
||||
deprecated_architecture = True
|
||||
deprecated_architecture = bit32 and installation_type != "Container"
|
||||
if deprecated_method or deprecated_architecture:
|
||||
issue_id = "deprecated"
|
||||
if deprecated_method:
|
||||
@ -430,7 +441,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
||||
hass,
|
||||
DOMAIN,
|
||||
issue_id,
|
||||
breaks_in_ha_version="2025.12.0",
|
||||
learn_more_url=DEPRECATION_URL,
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
|
@ -107,9 +107,9 @@
|
||||
"title": "Deprecation notice: 32-bit architecture",
|
||||
"description": "This system uses 32-bit hardware (`{arch}`), which has been deprecated and will no longer receive updates after the release of Home Assistant 2025.12. As your hardware is no longer capable of running newer versions of Home Assistant, you will need to migrate to new hardware."
|
||||
},
|
||||
"deprecated_container_armv7": {
|
||||
"deprecated_container": {
|
||||
"title": "[%key:component::homeassistant::issues::deprecated_architecture::title%]",
|
||||
"description": "This system is running on a 32-bit operating system (`armv7`), which has been deprecated and will no longer receive updates after the release of Home Assistant 2025.12. Check if your system is capable of running a 64-bit operating system. If not, you will need to migrate to new hardware."
|
||||
"description": "This system is running on a 32-bit operating system (`{arch}`), which has been deprecated and will no longer receive updates after the release of Home Assistant 2025.12. Check if your system is capable of running a 64-bit operating system. If not, you will need to migrate to new hardware."
|
||||
},
|
||||
"deprecated_os_aarch64": {
|
||||
"title": "[%key:component::homeassistant::issues::deprecated_architecture::title%]",
|
||||
|
@ -260,3 +260,16 @@ 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,7 +1156,11 @@ def test_deprecated_constants(
|
||||
("rpi2", "deprecated_os_armv7"),
|
||||
],
|
||||
)
|
||||
async def test_deprecated_installation_issue_aarch64(
|
||||
@pytest.mark.parametrize(
|
||||
"arch",
|
||||
["armv7"],
|
||||
)
|
||||
async def test_deprecated_installation_issue_os_armv7(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
@ -1167,18 +1171,15 @@ async def test_deprecated_installation_issue_aarch64(
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.hassio.async_get_system_info",
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": "armv7",
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": "armv7",
|
||||
},
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=True,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_os_info", return_value={"board": board}
|
||||
@ -1228,7 +1229,7 @@ async def test_deprecated_installation_issue_aarch64(
|
||||
"armv7",
|
||||
],
|
||||
)
|
||||
async def test_deprecated_installation_issue_32bit_method(
|
||||
async def test_deprecated_installation_issue_32bit_os(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
@ -1238,18 +1239,15 @@ async def test_deprecated_installation_issue_32bit_method(
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.hassio.async_get_system_info",
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": arch,
|
||||
},
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=True,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_os_info",
|
||||
@ -1308,18 +1306,15 @@ async def test_deprecated_installation_issue_32bit_supervised(
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.hassio.async_get_system_info",
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Supervised",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Supervised",
|
||||
"arch": arch,
|
||||
},
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=True,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_os_info",
|
||||
@ -1365,6 +1360,75 @@ async def test_deprecated_installation_issue_32bit_supervised(
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"arch",
|
||||
[
|
||||
"amd64",
|
||||
"aarch64",
|
||||
],
|
||||
)
|
||||
async def test_deprecated_installation_issue_64bit_supervised(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
arch: str,
|
||||
) -> None:
|
||||
"""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,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_os_info",
|
||||
return_value={"board": "generic-x86-64"},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_info", return_value={"hassos": None}
|
||||
),
|
||||
patch("homeassistant.components.hardware.async_setup", return_value=True),
|
||||
):
|
||||
assert await async_setup_component(hass, "homeassistant", {})
|
||||
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
freezer.tick(REQUEST_REFRESH_DELAY)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
await hass.services.async_call(
|
||||
"homeassistant",
|
||||
"update_entity",
|
||||
{
|
||||
"entity_id": [
|
||||
"update.home_assistant_core_update",
|
||||
"update.home_assistant_supervisor_update",
|
||||
]
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
freezer.tick(HASSIO_UPDATE_INTERVAL)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
issue = issue_registry.async_get_issue("homeassistant", "deprecated_method")
|
||||
assert issue.domain == "homeassistant"
|
||||
assert issue.severity == ir.IssueSeverity.WARNING
|
||||
assert issue.translation_placeholders == {
|
||||
"installation_type": "Supervised",
|
||||
"arch": arch,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("board", "issue_id"),
|
||||
[
|
||||
@ -1382,18 +1446,15 @@ async def test_deprecated_installation_issue_supported_board(
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.hassio.async_get_system_info",
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": "aarch64",
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant OS",
|
||||
"arch": "aarch64",
|
||||
},
|
||||
"homeassistant.components.hassio._is_32_bit",
|
||||
return_value=False,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.hassio.get_os_info", return_value={"board": board}
|
||||
|
@ -648,18 +648,24 @@ async def test_reload_all(
|
||||
"armv7",
|
||||
],
|
||||
)
|
||||
async def test_deprecated_installation_issue_32bit_method(
|
||||
async def test_deprecated_installation_issue_32bit_core(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
arch: str,
|
||||
) -> None:
|
||||
"""Test deprecated installation issue."""
|
||||
with patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Core",
|
||||
"arch": arch,
|
||||
},
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Core",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant._is_32_bit",
|
||||
return_value=True,
|
||||
),
|
||||
):
|
||||
assert await async_setup_component(hass, HOMEASSISTANT_DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
@ -679,48 +685,28 @@ async def test_deprecated_installation_issue_32bit_method(
|
||||
@pytest.mark.parametrize(
|
||||
"arch",
|
||||
[
|
||||
"i386",
|
||||
"armhf",
|
||||
"aarch64",
|
||||
"generic-x86-64",
|
||||
],
|
||||
)
|
||||
async def test_deprecated_installation_issue_32bit(
|
||||
async def test_deprecated_installation_issue_64bit_core(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
arch: str,
|
||||
) -> None:
|
||||
"""Test deprecated installation issue."""
|
||||
with patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Container",
|
||||
"arch": arch,
|
||||
},
|
||||
):
|
||||
assert await async_setup_component(hass, HOMEASSISTANT_DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
issue = issue_registry.async_get_issue(
|
||||
HOMEASSISTANT_DOMAIN, "deprecated_architecture"
|
||||
)
|
||||
assert issue.domain == HOMEASSISTANT_DOMAIN
|
||||
assert issue.severity == ir.IssueSeverity.WARNING
|
||||
assert issue.translation_placeholders == {
|
||||
"installation_type": "Container",
|
||||
"arch": arch,
|
||||
}
|
||||
|
||||
|
||||
async def test_deprecated_installation_issue_method(
|
||||
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||
) -> None:
|
||||
"""Test deprecated installation issue."""
|
||||
with patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Core",
|
||||
"arch": "generic-x86-64",
|
||||
},
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Core",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant._is_32_bit",
|
||||
return_value=False,
|
||||
),
|
||||
):
|
||||
assert await async_setup_component(hass, HOMEASSISTANT_DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
@ -731,28 +717,46 @@ async def test_deprecated_installation_issue_method(
|
||||
assert issue.severity == ir.IssueSeverity.WARNING
|
||||
assert issue.translation_placeholders == {
|
||||
"installation_type": "Core",
|
||||
"arch": "generic-x86-64",
|
||||
"arch": arch,
|
||||
}
|
||||
|
||||
|
||||
async def test_deprecated_installation_issue_armv7_container(
|
||||
@pytest.mark.parametrize(
|
||||
"arch",
|
||||
[
|
||||
"i386",
|
||||
"armv7",
|
||||
"armhf",
|
||||
],
|
||||
)
|
||||
async def test_deprecated_installation_issue_32bit(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
arch: str,
|
||||
) -> None:
|
||||
"""Test deprecated installation issue."""
|
||||
with patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Container",
|
||||
"arch": "armv7",
|
||||
},
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.homeassistant.async_get_system_info",
|
||||
return_value={
|
||||
"installation_type": "Home Assistant Container",
|
||||
"arch": arch,
|
||||
},
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant._is_32_bit",
|
||||
return_value=True,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant._get_arch",
|
||||
return_value=arch,
|
||||
),
|
||||
):
|
||||
assert await async_setup_component(hass, HOMEASSISTANT_DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
issue = issue_registry.async_get_issue(
|
||||
HOMEASSISTANT_DOMAIN, "deprecated_container_armv7"
|
||||
)
|
||||
issue = issue_registry.async_get_issue(HOMEASSISTANT_DOMAIN, "deprecated_container")
|
||||
assert issue.domain == HOMEASSISTANT_DOMAIN
|
||||
assert issue.severity == ir.IssueSeverity.WARNING
|
||||
assert issue.translation_placeholders == {"arch": arch}
|
||||
|
Reference in New Issue
Block a user