Add docker config repair for supervisor issue (#93820)
parent
05c3d8bb37
commit
c25b26214b
|
@ -299,7 +299,7 @@ def get_supervisor_info(hass: HomeAssistant) -> dict[str, Any] | None:
|
|||
|
||||
@callback
|
||||
@bind_hass
|
||||
def get_addons_info(hass):
|
||||
def get_addons_info(hass: HomeAssistant) -> dict[str, dict[str, Any]] | None:
|
||||
"""Return Addons info.
|
||||
|
||||
Async friendly.
|
||||
|
@ -367,6 +367,16 @@ def get_core_info(hass: HomeAssistant) -> dict[str, Any] | None:
|
|||
return hass.data.get(DATA_CORE_INFO)
|
||||
|
||||
|
||||
@callback
|
||||
@bind_hass
|
||||
def get_issues_info(hass: HomeAssistant) -> SupervisorIssues | None:
|
||||
"""Return Supervisor issues info.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
return hass.data.get(DATA_KEY_SUPERVISOR_ISSUES)
|
||||
|
||||
|
||||
@callback
|
||||
@bind_hass
|
||||
def is_hassio(hass: HomeAssistant) -> bool:
|
||||
|
@ -778,7 +788,7 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
|
||||
new_data: dict[str, Any] = {}
|
||||
supervisor_info = get_supervisor_info(self.hass) or {}
|
||||
addons_info = get_addons_info(self.hass)
|
||||
addons_info = get_addons_info(self.hass) or {}
|
||||
addons_stats = get_addons_stats(self.hass)
|
||||
addons_changelogs = get_addons_changelogs(self.hass)
|
||||
store_data = get_store(self.hass) or {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""Hass.io const variables."""
|
||||
from enum import Enum
|
||||
from homeassistant.backports.enum import StrEnum
|
||||
|
||||
DOMAIN = "hassio"
|
||||
|
||||
|
@ -77,9 +77,12 @@ DATA_KEY_HOST = "host"
|
|||
DATA_KEY_SUPERVISOR_ISSUES = "supervisor_issues"
|
||||
|
||||
PLACEHOLDER_KEY_REFERENCE = "reference"
|
||||
PLACEHOLDER_KEY_COMPONENTS = "components"
|
||||
|
||||
ISSUE_KEY_SYSTEM_DOCKER_CONFIG = "issue_system_docker_config"
|
||||
|
||||
|
||||
class SupervisorEntityModel(str, Enum):
|
||||
class SupervisorEntityModel(StrEnum):
|
||||
"""Supervisor entity model."""
|
||||
|
||||
ADDON = "Home Assistant Add-on"
|
||||
|
@ -87,3 +90,17 @@ class SupervisorEntityModel(str, Enum):
|
|||
CORE = "Home Assistant Core"
|
||||
SUPERVIOSR = "Home Assistant Supervisor"
|
||||
HOST = "Home Assistant Host"
|
||||
|
||||
|
||||
class SupervisorIssueContext(StrEnum):
|
||||
"""Context for supervisor issues."""
|
||||
|
||||
ADDON = "addon"
|
||||
CORE = "core"
|
||||
DNS_SERVER = "dns_server"
|
||||
MOUNT = "mount"
|
||||
OS = "os"
|
||||
PLUGIN = "plugin"
|
||||
SUPERVISOR = "supervisor"
|
||||
STORE = "store"
|
||||
SYSTEM = "system"
|
||||
|
|
|
@ -35,8 +35,10 @@ from .const import (
|
|||
EVENT_SUPERVISOR_EVENT,
|
||||
EVENT_SUPERVISOR_UPDATE,
|
||||
EVENT_SUPPORTED_CHANGED,
|
||||
ISSUE_KEY_SYSTEM_DOCKER_CONFIG,
|
||||
PLACEHOLDER_KEY_REFERENCE,
|
||||
UPDATE_KEY_SUPERVISOR,
|
||||
SupervisorIssueContext,
|
||||
)
|
||||
from .handler import HassIO, HassioAPIError
|
||||
|
||||
|
@ -88,6 +90,7 @@ ISSUE_KEYS_FOR_REPAIRS = {
|
|||
"issue_mount_mount_failed",
|
||||
"issue_system_multiple_data_disks",
|
||||
"issue_system_reboot_required",
|
||||
ISSUE_KEY_SYSTEM_DOCKER_CONFIG,
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -107,22 +110,22 @@ class Suggestion:
|
|||
"""Suggestion from Supervisor which resolves an issue."""
|
||||
|
||||
uuid: str
|
||||
type_: str
|
||||
context: str
|
||||
type: str
|
||||
context: SupervisorIssueContext
|
||||
reference: str | None = None
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
"""Get key for suggestion (combination of context and type)."""
|
||||
return f"{self.context}_{self.type_}"
|
||||
return f"{self.context}_{self.type}"
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: SuggestionDataType) -> Suggestion:
|
||||
"""Convert from dictionary representation."""
|
||||
return cls(
|
||||
uuid=data["uuid"],
|
||||
type_=data["type"],
|
||||
context=data["context"],
|
||||
type=data["type"],
|
||||
context=SupervisorIssueContext(data["context"]),
|
||||
reference=data["reference"],
|
||||
)
|
||||
|
||||
|
@ -142,15 +145,15 @@ class Issue:
|
|||
"""Issue from Supervisor."""
|
||||
|
||||
uuid: str
|
||||
type_: str
|
||||
context: str
|
||||
type: str
|
||||
context: SupervisorIssueContext
|
||||
reference: str | None = None
|
||||
suggestions: list[Suggestion] = field(default_factory=list, compare=False)
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
"""Get key for issue (combination of context and type)."""
|
||||
return f"issue_{self.context}_{self.type_}"
|
||||
return f"issue_{self.context}_{self.type}"
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: IssueDataType) -> Issue:
|
||||
|
@ -158,8 +161,8 @@ class Issue:
|
|||
suggestions: list[SuggestionDataType] = data.get("suggestions", [])
|
||||
return cls(
|
||||
uuid=data["uuid"],
|
||||
type_=data["type"],
|
||||
context=data["context"],
|
||||
type=data["type"],
|
||||
context=SupervisorIssueContext(data["context"]),
|
||||
reference=data["reference"],
|
||||
suggestions=[
|
||||
Suggestion.from_dict(suggestion) for suggestion in suggestions
|
||||
|
@ -242,6 +245,11 @@ class SupervisorIssues:
|
|||
|
||||
self._unsupported_reasons = reasons
|
||||
|
||||
@property
|
||||
def issues(self) -> set[Issue]:
|
||||
"""Get issues."""
|
||||
return set(self._issues.values())
|
||||
|
||||
def add_issue(self, issue: Issue) -> None:
|
||||
"""Add or update an issue in the list. Create or update a repair if necessary."""
|
||||
if issue.key in ISSUE_KEYS_FOR_REPAIRS:
|
||||
|
@ -263,20 +271,10 @@ class SupervisorIssues:
|
|||
async def add_issue_from_data(self, data: IssueDataType) -> None:
|
||||
"""Add issue from data to list after getting latest suggestions."""
|
||||
try:
|
||||
suggestions = (await self._client.get_suggestions_for_issue(data["uuid"]))[
|
||||
ATTR_SUGGESTIONS
|
||||
]
|
||||
self.add_issue(
|
||||
Issue(
|
||||
uuid=data["uuid"],
|
||||
type_=data["type"],
|
||||
context=data["context"],
|
||||
reference=data["reference"],
|
||||
suggestions=[
|
||||
Suggestion.from_dict(suggestion) for suggestion in suggestions
|
||||
],
|
||||
)
|
||||
)
|
||||
data["suggestions"] = (
|
||||
await self._client.get_suggestions_for_issue(data["uuid"])
|
||||
)[ATTR_SUGGESTIONS]
|
||||
self.add_issue(Issue.from_dict(data))
|
||||
except HassioAPIError:
|
||||
_LOGGER.error(
|
||||
"Could not get suggestions for supervisor issue %s, skipping it",
|
||||
|
|
|
@ -10,9 +10,15 @@ from homeassistant.components.repairs import RepairsFlow
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import DATA_KEY_SUPERVISOR_ISSUES, PLACEHOLDER_KEY_REFERENCE
|
||||
from . import get_addons_info, get_issues_info
|
||||
from .const import (
|
||||
ISSUE_KEY_SYSTEM_DOCKER_CONFIG,
|
||||
PLACEHOLDER_KEY_COMPONENTS,
|
||||
PLACEHOLDER_KEY_REFERENCE,
|
||||
SupervisorIssueContext,
|
||||
)
|
||||
from .handler import HassioAPIError, async_apply_suggestion
|
||||
from .issues import Issue, Suggestion, SupervisorIssues
|
||||
from .issues import Issue, Suggestion
|
||||
|
||||
SUGGESTION_CONFIRMATION_REQUIRED = {"system_execute_reboot"}
|
||||
|
||||
|
@ -37,10 +43,8 @@ class SupervisorIssueRepairFlow(RepairsFlow):
|
|||
@property
|
||||
def issue(self) -> Issue | None:
|
||||
"""Get associated issue."""
|
||||
if not self._issue:
|
||||
supervisor_issues: SupervisorIssues = self.hass.data[
|
||||
DATA_KEY_SUPERVISOR_ISSUES
|
||||
]
|
||||
supervisor_issues = get_issues_info(self.hass)
|
||||
if not self._issue and supervisor_issues:
|
||||
self._issue = supervisor_issues.get_issue(self._issue_id)
|
||||
|
||||
return self._issue
|
||||
|
@ -121,10 +125,49 @@ class SupervisorIssueRepairFlow(RepairsFlow):
|
|||
return _async_step
|
||||
|
||||
|
||||
class DockerConfigIssueRepairFlow(SupervisorIssueRepairFlow):
|
||||
"""Handler for docker config issue fixing flow."""
|
||||
|
||||
@property
|
||||
def description_placeholders(self) -> dict[str, str] | None:
|
||||
"""Get description placeholders for steps."""
|
||||
placeholders = {PLACEHOLDER_KEY_COMPONENTS: ""}
|
||||
supervisor_issues = get_issues_info(self.hass)
|
||||
if supervisor_issues and self.issue:
|
||||
addons = get_addons_info(self.hass) or {}
|
||||
components: list[str] = []
|
||||
for issue in supervisor_issues.issues:
|
||||
if issue.key == self.issue.key or issue.type != self.issue.type:
|
||||
continue
|
||||
|
||||
if issue.context == SupervisorIssueContext.CORE:
|
||||
components.insert(0, "Home Assistant")
|
||||
elif issue.context == SupervisorIssueContext.ADDON:
|
||||
components.append(
|
||||
next(
|
||||
(
|
||||
info["name"]
|
||||
for slug, info in addons.items()
|
||||
if slug == issue.reference
|
||||
),
|
||||
issue.reference or "",
|
||||
)
|
||||
)
|
||||
|
||||
placeholders[PLACEHOLDER_KEY_COMPONENTS] = "\n- ".join(components)
|
||||
|
||||
return placeholders
|
||||
|
||||
|
||||
async def async_create_fix_flow(
|
||||
hass: HomeAssistant,
|
||||
issue_id: str,
|
||||
data: dict[str, str | int | float | None] | None,
|
||||
) -> RepairsFlow:
|
||||
"""Create flow."""
|
||||
supervisor_issues = get_issues_info(hass)
|
||||
issue = supervisor_issues and supervisor_issues.get_issue(issue_id)
|
||||
if issue and issue.key == ISSUE_KEY_SYSTEM_DOCKER_CONFIG:
|
||||
return DockerConfigIssueRepairFlow(issue_id)
|
||||
|
||||
return SupervisorIssueRepairFlow(issue_id)
|
||||
|
|
|
@ -30,7 +30,20 @@
|
|||
}
|
||||
},
|
||||
"abort": {
|
||||
"apply_suggestion_fail": "Could not apply the fix. Check the supervisor logs for more details."
|
||||
"apply_suggestion_fail": "Could not apply the fix. Check the Supervisor logs for more details."
|
||||
}
|
||||
}
|
||||
},
|
||||
"issue_system_docker_config": {
|
||||
"title": "Restart(s) required",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"system_execute_rebuild": {
|
||||
"description": "The default configuration for add-ons and Home Assistant has changed. To update the configuration with the new defaults, a restart is required for the following:\n\n- {components}"
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"apply_suggestion_fail": "One or more of the restarts failed. Check the Supervisor logs for more details."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -43,7 +56,7 @@
|
|||
}
|
||||
},
|
||||
"abort": {
|
||||
"apply_suggestion_fail": "Could not rename the filesystem. Check the supervisor logs for more details."
|
||||
"apply_suggestion_fail": "Could not rename the filesystem. Check the Supervisor logs for more details."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -56,7 +69,7 @@
|
|||
}
|
||||
},
|
||||
"abort": {
|
||||
"apply_suggestion_fail": "Could not reboot the system. Check the supervisor logs for more details."
|
||||
"apply_suggestion_fail": "Could not reboot the system. Check the Supervisor logs for more details."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -98,6 +98,10 @@ def all_setup_requests(
|
|||
aioclient_mock: AiohttpClientMocker, request: pytest.FixtureRequest
|
||||
):
|
||||
"""Mock all setup requests."""
|
||||
include_addons = hasattr(request, "param") and request.param.get(
|
||||
"include_addons", False
|
||||
)
|
||||
|
||||
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
|
||||
aioclient_mock.post("http://127.0.0.1/supervisor/options", json={"result": "ok"})
|
||||
|
@ -157,7 +161,30 @@ def all_setup_requests(
|
|||
"version": "1.0.0",
|
||||
"version_latest": "1.0.0",
|
||||
"auto_update": True,
|
||||
"addons": [],
|
||||
"addons": [
|
||||
{
|
||||
"name": "test",
|
||||
"slug": "test",
|
||||
"update_available": False,
|
||||
"version": "1.0.0",
|
||||
"version_latest": "1.0.0",
|
||||
"repository": "core",
|
||||
"state": "started",
|
||||
"icon": False,
|
||||
},
|
||||
{
|
||||
"name": "test2",
|
||||
"slug": "test2",
|
||||
"update_available": False,
|
||||
"version": "1.0.0",
|
||||
"version_latest": "1.0.0",
|
||||
"repository": "core",
|
||||
"state": "started",
|
||||
"icon": False,
|
||||
},
|
||||
]
|
||||
if include_addons
|
||||
else [],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
@ -165,3 +192,106 @@ def all_setup_requests(
|
|||
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
||||
)
|
||||
aioclient_mock.post("http://127.0.0.1/refresh_updates", json={"result": "ok"})
|
||||
|
||||
aioclient_mock.get("http://127.0.0.1/addons/test/changelog", text="")
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/addons/test/info",
|
||||
json={
|
||||
"result": "ok",
|
||||
"data": {
|
||||
"name": "test",
|
||||
"slug": "test",
|
||||
"update_available": False,
|
||||
"version": "1.0.0",
|
||||
"version_latest": "1.0.0",
|
||||
"repository": "core",
|
||||
"state": "started",
|
||||
"icon": False,
|
||||
"url": "https://github.com/home-assistant/addons/test",
|
||||
"auto_update": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
aioclient_mock.get("http://127.0.0.1/addons/test2/changelog", text="")
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/addons/test2/info",
|
||||
json={
|
||||
"result": "ok",
|
||||
"data": {
|
||||
"name": "test2",
|
||||
"slug": "test2",
|
||||
"update_available": False,
|
||||
"version": "1.0.0",
|
||||
"version_latest": "1.0.0",
|
||||
"repository": "core",
|
||||
"state": "started",
|
||||
"icon": False,
|
||||
"url": "https://github.com",
|
||||
"auto_update": False,
|
||||
},
|
||||
},
|
||||
)
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/core/stats",
|
||||
json={
|
||||
"result": "ok",
|
||||
"data": {
|
||||
"cpu_percent": 0.99,
|
||||
"memory_usage": 182611968,
|
||||
"memory_limit": 3977146368,
|
||||
"memory_percent": 4.59,
|
||||
"network_rx": 362570232,
|
||||
"network_tx": 82374138,
|
||||
"blk_read": 46010945536,
|
||||
"blk_write": 15051526144,
|
||||
},
|
||||
},
|
||||
)
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/stats",
|
||||
json={
|
||||
"result": "ok",
|
||||
"data": {
|
||||
"cpu_percent": 0.99,
|
||||
"memory_usage": 182611968,
|
||||
"memory_limit": 3977146368,
|
||||
"memory_percent": 4.59,
|
||||
"network_rx": 362570232,
|
||||
"network_tx": 82374138,
|
||||
"blk_read": 46010945536,
|
||||
"blk_write": 15051526144,
|
||||
},
|
||||
},
|
||||
)
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/addons/test/stats",
|
||||
json={
|
||||
"result": "ok",
|
||||
"data": {
|
||||
"cpu_percent": 0.99,
|
||||
"memory_usage": 182611968,
|
||||
"memory_limit": 3977146368,
|
||||
"memory_percent": 4.59,
|
||||
"network_rx": 362570232,
|
||||
"network_tx": 82374138,
|
||||
"blk_read": 46010945536,
|
||||
"blk_write": 15051526144,
|
||||
},
|
||||
},
|
||||
)
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/addons/test2/stats",
|
||||
json={
|
||||
"result": "ok",
|
||||
"data": {
|
||||
"cpu_percent": 0.8,
|
||||
"memory_usage": 51941376,
|
||||
"memory_limit": 3977146368,
|
||||
"memory_percent": 1.31,
|
||||
"network_rx": 31338284,
|
||||
"network_tx": 15692900,
|
||||
"blk_read": 740077568,
|
||||
"blk_write": 6004736,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
@ -496,7 +496,7 @@ async def test_supervisor_issues(
|
|||
{
|
||||
"uuid": "1237",
|
||||
"type": "should_not_be_repair",
|
||||
"context": "fake",
|
||||
"context": "os",
|
||||
"reference": None,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -19,16 +19,11 @@ from tests.typing import ClientSessionGenerator
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_repairs(hass):
|
||||
async def setup_repairs(hass: HomeAssistant):
|
||||
"""Set up the repairs integration."""
|
||||
assert await async_setup_component(hass, REPAIRS_DOMAIN, {REPAIRS_DOMAIN: {}})
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def mock_all(all_setup_requests):
|
||||
"""Mock all setup requests."""
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def fixture_supervisor_environ():
|
||||
"""Mock os environ for supervisor."""
|
||||
|
@ -40,9 +35,10 @@ async def test_supervisor_issue_repair_flow(
|
|||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
hass_client: ClientSessionGenerator,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
all_setup_requests,
|
||||
) -> None:
|
||||
"""Test fix flow for supervisor issue."""
|
||||
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
||||
mock_resolution_info(
|
||||
aioclient_mock,
|
||||
issues=[
|
||||
|
@ -63,8 +59,7 @@ async def test_supervisor_issue_repair_flow(
|
|||
],
|
||||
)
|
||||
|
||||
result = await async_setup_component(hass, "hassio", {})
|
||||
assert result
|
||||
assert await async_setup_component(hass, "hassio", {})
|
||||
|
||||
repair_issue = issue_registry.async_get_issue(domain="hassio", issue_id="1234")
|
||||
assert repair_issue
|
||||
|
@ -119,9 +114,10 @@ async def test_supervisor_issue_repair_flow_with_multiple_suggestions(
|
|||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
hass_client: ClientSessionGenerator,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
all_setup_requests,
|
||||
) -> None:
|
||||
"""Test fix flow for supervisor issue with multiple suggestions."""
|
||||
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
||||
mock_resolution_info(
|
||||
aioclient_mock,
|
||||
issues=[
|
||||
|
@ -148,8 +144,7 @@ async def test_supervisor_issue_repair_flow_with_multiple_suggestions(
|
|||
],
|
||||
)
|
||||
|
||||
result = await async_setup_component(hass, "hassio", {})
|
||||
assert result
|
||||
assert await async_setup_component(hass, "hassio", {})
|
||||
|
||||
repair_issue = issue_registry.async_get_issue(domain="hassio", issue_id="1234")
|
||||
assert repair_issue
|
||||
|
@ -214,9 +209,10 @@ async def test_supervisor_issue_repair_flow_with_multiple_suggestions_and_confir
|
|||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
hass_client: ClientSessionGenerator,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
all_setup_requests,
|
||||
) -> None:
|
||||
"""Test fix flow for supervisor issue with multiple suggestions and choice requires confirmation."""
|
||||
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
||||
mock_resolution_info(
|
||||
aioclient_mock,
|
||||
issues=[
|
||||
|
@ -243,8 +239,7 @@ async def test_supervisor_issue_repair_flow_with_multiple_suggestions_and_confir
|
|||
],
|
||||
)
|
||||
|
||||
result = await async_setup_component(hass, "hassio", {})
|
||||
assert result
|
||||
assert await async_setup_component(hass, "hassio", {})
|
||||
|
||||
repair_issue = issue_registry.async_get_issue(domain="hassio", issue_id="1234")
|
||||
assert repair_issue
|
||||
|
@ -327,9 +322,10 @@ async def test_supervisor_issue_repair_flow_skip_confirmation(
|
|||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
hass_client: ClientSessionGenerator,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
all_setup_requests,
|
||||
) -> None:
|
||||
"""Test confirmation skipped for fix flow for supervisor issue with one suggestion."""
|
||||
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
||||
mock_resolution_info(
|
||||
aioclient_mock,
|
||||
issues=[
|
||||
|
@ -350,8 +346,7 @@ async def test_supervisor_issue_repair_flow_skip_confirmation(
|
|||
],
|
||||
)
|
||||
|
||||
result = await async_setup_component(hass, "hassio", {})
|
||||
assert result
|
||||
assert await async_setup_component(hass, "hassio", {})
|
||||
|
||||
repair_issue = issue_registry.async_get_issue(domain="hassio", issue_id="1234")
|
||||
assert repair_issue
|
||||
|
@ -406,9 +401,10 @@ async def test_mount_failed_repair_flow(
|
|||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
hass_client: ClientSessionGenerator,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
all_setup_requests,
|
||||
) -> None:
|
||||
"""Test repair flow for mount_failed issue."""
|
||||
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
||||
mock_resolution_info(
|
||||
aioclient_mock,
|
||||
issues=[
|
||||
|
@ -435,8 +431,7 @@ async def test_mount_failed_repair_flow(
|
|||
],
|
||||
)
|
||||
|
||||
result = await async_setup_component(hass, "hassio", {})
|
||||
assert result
|
||||
assert await async_setup_component(hass, "hassio", {})
|
||||
|
||||
repair_issue = issue_registry.async_get_issue(domain="hassio", issue_id="1234")
|
||||
assert repair_issue
|
||||
|
@ -499,3 +494,113 @@ async def test_mount_failed_repair_flow(
|
|||
str(aioclient_mock.mock_calls[-1][1])
|
||||
== "http://127.0.0.1/resolution/suggestion/1235"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"all_setup_requests", [{"include_addons": True}], indirect=True
|
||||
)
|
||||
async def test_supervisor_issue_docker_config_repair_flow(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
hass_client: ClientSessionGenerator,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
all_setup_requests,
|
||||
) -> None:
|
||||
"""Test fix flow for supervisor issue."""
|
||||
mock_resolution_info(
|
||||
aioclient_mock,
|
||||
issues=[
|
||||
{
|
||||
"uuid": "1234",
|
||||
"type": "docker_config",
|
||||
"context": "system",
|
||||
"reference": None,
|
||||
"suggestions": [
|
||||
{
|
||||
"uuid": "1235",
|
||||
"type": "execute_rebuild",
|
||||
"context": "system",
|
||||
"reference": None,
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"uuid": "1236",
|
||||
"type": "docker_config",
|
||||
"context": "core",
|
||||
"reference": None,
|
||||
"suggestions": [
|
||||
{
|
||||
"uuid": "1237",
|
||||
"type": "execute_rebuild",
|
||||
"context": "core",
|
||||
"reference": None,
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"uuid": "1238",
|
||||
"type": "docker_config",
|
||||
"context": "addon",
|
||||
"reference": "test",
|
||||
"suggestions": [
|
||||
{
|
||||
"uuid": "1239",
|
||||
"type": "execute_rebuild",
|
||||
"context": "addon",
|
||||
"reference": "test",
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
assert await async_setup_component(hass, "hassio", {})
|
||||
|
||||
repair_issue = issue_registry.async_get_issue(domain="hassio", issue_id="1234")
|
||||
assert repair_issue
|
||||
|
||||
client = await hass_client()
|
||||
|
||||
resp = await client.post(
|
||||
"/api/repairs/issues/fix",
|
||||
json={"handler": "hassio", "issue_id": repair_issue.issue_id},
|
||||
)
|
||||
|
||||
assert resp.status == HTTPStatus.OK
|
||||
data = await resp.json()
|
||||
|
||||
flow_id = data["flow_id"]
|
||||
assert data == {
|
||||
"type": "form",
|
||||
"flow_id": flow_id,
|
||||
"handler": "hassio",
|
||||
"step_id": "system_execute_rebuild",
|
||||
"data_schema": [],
|
||||
"errors": None,
|
||||
"description_placeholders": {"components": "Home Assistant\n- test"},
|
||||
"last_step": True,
|
||||
}
|
||||
|
||||
resp = await client.post(f"/api/repairs/issues/fix/{flow_id}")
|
||||
|
||||
assert resp.status == HTTPStatus.OK
|
||||
data = await resp.json()
|
||||
|
||||
flow_id = data["flow_id"]
|
||||
assert data == {
|
||||
"version": 1,
|
||||
"type": "create_entry",
|
||||
"flow_id": flow_id,
|
||||
"handler": "hassio",
|
||||
"description": None,
|
||||
"description_placeholders": None,
|
||||
}
|
||||
|
||||
assert not issue_registry.async_get_issue(domain="hassio", issue_id="1234")
|
||||
|
||||
assert aioclient_mock.mock_calls[-1][0] == "post"
|
||||
assert (
|
||||
str(aioclient_mock.mock_calls[-1][1])
|
||||
== "http://127.0.0.1/resolution/suggestion/1235"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue