Attempt plugin update before failing job condition (#3796)

This commit is contained in:
Mike Degatano 2022-08-17 01:36:05 -04:00 committed by GitHub
parent 5fc9484f73
commit 2cd7f9d1b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 10 deletions

View File

@ -92,7 +92,7 @@ class Job(CoreSysAttributes):
# Handle condition # Handle condition
if self.conditions: if self.conditions:
try: try:
self._check_conditions() await self._check_conditions()
except JobConditionException as err: except JobConditionException as err:
error_msg = str(err) error_msg = str(err)
if self.on_condition is None: if self.on_condition is None:
@ -150,7 +150,7 @@ class Job(CoreSysAttributes):
return wrapper return wrapper
def _check_conditions(self): async def _check_conditions(self):
"""Check conditions.""" """Check conditions."""
used_conditions = set(self.conditions) - set(self.sys_jobs.ignore_conditions) used_conditions = set(self.conditions) - set(self.sys_jobs.ignore_conditions)
ignored_conditions = set(self.conditions) & set(self.sys_jobs.ignore_conditions) ignored_conditions = set(self.conditions) & set(self.sys_jobs.ignore_conditions)
@ -238,13 +238,22 @@ class Job(CoreSysAttributes):
f"'{self._method.__qualname__}' blocked from execution, supervisor needs to be updated first" f"'{self._method.__qualname__}' blocked from execution, supervisor needs to be updated first"
) )
if JobCondition.PLUGINS_UPDATED in self.conditions and 0 < len( if JobCondition.PLUGINS_UPDATED in self.conditions and (
[plugin for plugin in self.sys_plugins.all_plugins if plugin.need_update] out_of_date := [
plugin for plugin in self.sys_plugins.all_plugins if plugin.need_update
]
): ):
raise JobConditionException( errors = await asyncio.gather(
f"'{self._method.__qualname__}' blocked from execution, plugin(s) {', '.join([plugin.slug for plugin in self.sys_plugins.all_plugins if plugin.need_update])} need to be updated first" *[plugin.update() for plugin in out_of_date], return_exceptions=True
) )
if update_failures := [
out_of_date[i].slug for i in range(len(errors)) if errors[i] is not None
]:
raise JobConditionException(
f"'{self._method.__qualname__}' blocked from execution, was unable to update plugin(s) {', '.join(update_failures)} and all plugins must be up to date first"
)
async def _acquire_exection_limit(self) -> None: async def _acquire_exection_limit(self) -> None:
"""Process exection limits.""" """Process exection limits."""
if self.limit not in ( if self.limit not in (

View File

@ -11,7 +11,7 @@ from supervisor.const import AddonState, BusEvent
from supervisor.coresys import CoreSys from supervisor.coresys import CoreSys
from supervisor.docker.const import ContainerState from supervisor.docker.const import ContainerState
from supervisor.docker.monitor import DockerContainerStateEvent from supervisor.docker.monitor import DockerContainerStateEvent
from supervisor.exceptions import AddonsJobError from supervisor.exceptions import AddonsJobError, AudioUpdateError
from ..const import TEST_ADDON_SLUG from ..const import TEST_ADDON_SLUG
@ -287,6 +287,8 @@ async def test_install_update_fails_if_out_of_date(
with patch.object( with patch.object(
type(coresys.plugins.audio), "need_update", new=PropertyMock(return_value=True) type(coresys.plugins.audio), "need_update", new=PropertyMock(return_value=True)
), patch.object(
type(coresys.plugins.audio), "update", side_effect=AudioUpdateError
): ):
with pytest.raises(AddonsJobError): with pytest.raises(AddonsJobError):
await coresys.addons.install(TEST_ADDON_SLUG) await coresys.addons.install(TEST_ADDON_SLUG)

View File

@ -4,7 +4,7 @@ from unittest.mock import PropertyMock, patch
import pytest import pytest
from supervisor.coresys import CoreSys from supervisor.coresys import CoreSys
from supervisor.exceptions import HomeAssistantJobError from supervisor.exceptions import AudioUpdateError, HomeAssistantJobError
async def test_update_fails_if_out_of_date(coresys: CoreSys): async def test_update_fails_if_out_of_date(coresys: CoreSys):
@ -18,5 +18,9 @@ async def test_update_fails_if_out_of_date(coresys: CoreSys):
with patch.object( with patch.object(
type(coresys.plugins.audio), "need_update", new=PropertyMock(return_value=True) type(coresys.plugins.audio), "need_update", new=PropertyMock(return_value=True)
), pytest.raises(HomeAssistantJobError): ), patch.object(
type(coresys.plugins.audio), "update", side_effect=AudioUpdateError
), pytest.raises(
HomeAssistantJobError
):
await coresys.homeassistant.core.update() await coresys.homeassistant.core.update()

View File

@ -9,7 +9,12 @@ import time_machine
from supervisor.const import CoreState from supervisor.const import CoreState
from supervisor.coresys import CoreSys from supervisor.coresys import CoreSys
from supervisor.exceptions import HassioError, JobException, PluginJobError from supervisor.exceptions import (
AudioUpdateError,
HassioError,
JobException,
PluginJobError,
)
from supervisor.jobs.const import JobExecutionLimit from supervisor.jobs.const import JobExecutionLimit
from supervisor.jobs.decorator import Job, JobCondition from supervisor.jobs.decorator import Job, JobCondition
from supervisor.resolution.const import UnhealthyReason from supervisor.resolution.const import UnhealthyReason
@ -448,8 +453,11 @@ async def test_plugins_updated(coresys: CoreSys):
with patch.object( with patch.object(
type(coresys.plugins.audio), "need_update", new=PropertyMock(return_value=True) type(coresys.plugins.audio), "need_update", new=PropertyMock(return_value=True)
), patch.object(
type(coresys.plugins.audio), "update", side_effect=[AudioUpdateError, None]
): ):
assert not await test.execute() assert not await test.execute()
assert await test.execute()
async def test_auto_update(coresys: CoreSys): async def test_auto_update(coresys: CoreSys):