mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-16 05:36:29 +00:00
Keep shared images on addon uninstall (#5259)
* Keep shared images on addon uninstall * Add missing step for mocking new addon in store
This commit is contained in:
parent
12d26b05af
commit
986b92aee4
@ -763,10 +763,12 @@ class Addon(AddonModel):
|
||||
limit=JobExecutionLimit.GROUP_ONCE,
|
||||
on_condition=AddonsJobError,
|
||||
)
|
||||
async def uninstall(self, *, remove_config: bool) -> None:
|
||||
async def uninstall(
|
||||
self, *, remove_config: bool, remove_image: bool = True
|
||||
) -> None:
|
||||
"""Uninstall and cleanup this addon."""
|
||||
try:
|
||||
await self.instance.remove()
|
||||
await self.instance.remove(remove_image=remove_image)
|
||||
except DockerError as err:
|
||||
raise AddonsError() from err
|
||||
|
||||
|
@ -185,7 +185,15 @@ class AddonManager(CoreSysAttributes):
|
||||
_LOGGER.warning("Add-on %s is not installed", slug)
|
||||
return
|
||||
|
||||
await self.local[slug].uninstall(remove_config=remove_config)
|
||||
shared_image = any(
|
||||
self.local[slug].image == addon.image
|
||||
and self.local[slug].version == addon.version
|
||||
for addon in self.installed
|
||||
if addon.slug != slug
|
||||
)
|
||||
await self.local[slug].uninstall(
|
||||
remove_config=remove_config, remove_image=not shared_image
|
||||
)
|
||||
|
||||
_LOGGER.info("Add-on '%s' successfully removed", slug)
|
||||
|
||||
|
@ -429,15 +429,17 @@ class DockerInterface(JobGroup):
|
||||
limit=JobExecutionLimit.GROUP_ONCE,
|
||||
on_condition=DockerJobError,
|
||||
)
|
||||
async def remove(self) -> None:
|
||||
async def remove(self, *, remove_image: bool = True) -> None:
|
||||
"""Remove Docker images."""
|
||||
# Cleanup container
|
||||
with suppress(DockerError):
|
||||
await self.stop()
|
||||
|
||||
await self.sys_run_in_executor(
|
||||
self.sys_docker.remove_image, self.image, self.version
|
||||
)
|
||||
if remove_image:
|
||||
await self.sys_run_in_executor(
|
||||
self.sys_docker.remove_image, self.image, self.version
|
||||
)
|
||||
|
||||
self._meta = None
|
||||
|
||||
@Job(
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Test addon manager."""
|
||||
|
||||
import asyncio
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, MagicMock, Mock, PropertyMock, patch
|
||||
|
||||
@ -24,6 +25,7 @@ from supervisor.exceptions import (
|
||||
DockerNotFound,
|
||||
)
|
||||
from supervisor.plugins.dns import PluginDns
|
||||
from supervisor.store.addon import AddonStore
|
||||
from supervisor.store.repository import Repository
|
||||
from supervisor.utils import check_exception_chain
|
||||
from supervisor.utils.common import write_json_file
|
||||
@ -454,3 +456,38 @@ async def test_watchdog_runs_during_update(
|
||||
await asyncio.sleep(0)
|
||||
start.assert_called_once()
|
||||
restart.assert_not_called()
|
||||
|
||||
|
||||
async def test_shared_image_kept_on_uninstall(
|
||||
coresys: CoreSys, install_addon_example: Addon
|
||||
):
|
||||
"""Test if two addons share an image it is not removed on uninstall."""
|
||||
# Clone example to a new mock copy so two share an image
|
||||
store_data = deepcopy(coresys.addons.store["local_example"].data)
|
||||
store = AddonStore(coresys, "local_example2", store_data)
|
||||
coresys.addons.store["local_example2"] = store
|
||||
coresys.addons.data.install(store)
|
||||
# pylint: disable-next=protected-access
|
||||
coresys.addons.data._data = coresys.addons.data._schema(coresys.addons.data._data)
|
||||
|
||||
example_2 = Addon(coresys, store.slug)
|
||||
coresys.addons.local[example_2.slug] = example_2
|
||||
|
||||
image = f"{install_addon_example.image}:{install_addon_example.version}"
|
||||
latest = f"{install_addon_example.image}:latest"
|
||||
|
||||
await coresys.addons.uninstall("local_example2")
|
||||
coresys.docker.images.remove.assert_not_called()
|
||||
assert not coresys.addons.get("local_example2", local_only=True)
|
||||
|
||||
await coresys.addons.uninstall("local_example")
|
||||
assert coresys.docker.images.remove.call_count == 2
|
||||
assert coresys.docker.images.remove.call_args_list[0].kwargs == {
|
||||
"image": latest,
|
||||
"force": True,
|
||||
}
|
||||
assert coresys.docker.images.remove.call_args_list[1].kwargs == {
|
||||
"image": image,
|
||||
"force": True,
|
||||
}
|
||||
assert not coresys.addons.get("local_example", local_only=True)
|
||||
|
Loading…
x
Reference in New Issue
Block a user