1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-02-15 07:27:13 +00:00

Reload ingress tokens on addon update and rebuild (#6556)

When an addon updates from having no ingress to having ingress, the
ingress token map was never rebuilt. Both update() and rebuild() called
_check_ingress_port() to assign a dynamic port but skipped the
sys_ingress.reload() call that registers the token. This caused
Ingress.get() to return None, resulting in a 503 error.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Stefan Agner
2026-02-11 21:20:08 +01:00
committed by GitHub
parent cc2da7284a
commit 7ae14b09a7
2 changed files with 79 additions and 1 deletions

View File

@@ -926,6 +926,10 @@ class Addon(AddonModel):
await self.sys_addons.data.update(store)
await self._check_ingress_port()
# Reload ingress tokens in case addon gained ingress support
if self.with_ingress:
await self.sys_ingress.reload()
# Cleanup
with suppress(DockerError):
await self.instance.cleanup(
@@ -979,6 +983,11 @@ class Addon(AddonModel):
await self.sys_addons.data.update(self.addon_store)
await self._check_ingress_port()
# Reload ingress tokens in case addon gained ingress support
if self.with_ingress:
await self.sys_ingress.reload()
_LOGGER.info("Add-on '%s' successfully rebuilt", self.slug)
finally:

View File

@@ -13,7 +13,7 @@ import pytest
from supervisor.addons.addon import Addon
from supervisor.arch import CpuArchManager
from supervisor.config import CoreConfig
from supervisor.const import AddonBoot, AddonStartup, AddonState, BusEvent
from supervisor.const import ATTR_INGRESS, AddonBoot, AddonStartup, AddonState, BusEvent
from supervisor.coresys import CoreSys
from supervisor.docker.addon import DockerAddon
from supervisor.docker.const import ContainerState
@@ -528,6 +528,75 @@ async def test_shared_image_kept_on_uninstall(
assert not coresys.addons.get("local_example", local_only=True)
@pytest.mark.usefixtures("tmp_supervisor_data", "path_extern")
async def test_update_reloads_ingress_tokens(
coresys: CoreSys,
install_addon_ssh: Addon,
container: DockerContainer,
):
"""Test ingress tokens are reloaded when addon gains ingress on update."""
container.show.return_value["State"]["Status"] = "stopped"
container.show.return_value["State"]["Running"] = False
install_addon_ssh.path_data.mkdir()
# Simulate addon was installed without ingress
coresys.addons.data.system[install_addon_ssh.slug][ATTR_INGRESS] = False
await install_addon_ssh.load()
await coresys.ingress.reload()
assert install_addon_ssh.ingress_token not in coresys.ingress.tokens
# Update store to version with ingress enabled
with patch(
"supervisor.store.data.read_json_or_yaml_file",
return_value=load_json_fixture("addon-config-add-image.json"),
):
await coresys.store.data.update()
assert install_addon_ssh.need_update is True
with (
patch.object(DockerInterface, "install"),
patch.object(DockerAddon, "is_running", return_value=False),
):
await coresys.addons.update(TEST_ADDON_SLUG)
# Ingress token should now be registered
assert install_addon_ssh.with_ingress is True
assert install_addon_ssh.ingress_token in coresys.ingress.tokens
@pytest.mark.usefixtures("tmp_supervisor_data", "path_extern")
async def test_rebuild_reloads_ingress_tokens(
coresys: CoreSys,
install_addon_ssh: Addon,
container: DockerContainer,
):
"""Test ingress tokens are reloaded when addon gains ingress on rebuild."""
container.show.return_value["State"]["Status"] = "stopped"
container.show.return_value["State"]["Running"] = False
install_addon_ssh.path_data.mkdir()
# Simulate addon was installed without ingress
coresys.addons.data.system[install_addon_ssh.slug][ATTR_INGRESS] = False
await install_addon_ssh.load()
await coresys.ingress.reload()
assert install_addon_ssh.ingress_token not in coresys.ingress.tokens
# Re-enable ingress in system data (rebuild pulls fresh store data)
coresys.addons.data.system[install_addon_ssh.slug][ATTR_INGRESS] = True
with (
patch.object(DockerAddon, "_build"),
patch.object(DockerAddon, "is_running", return_value=False),
patch.object(Addon, "need_build", new=PropertyMock(return_value=True)),
):
await coresys.addons.rebuild(TEST_ADDON_SLUG)
# Ingress token should now be registered
assert install_addon_ssh.with_ingress is True
assert install_addon_ssh.ingress_token in coresys.ingress.tokens
async def test_shared_image_kept_on_update(
coresys: CoreSys, install_addon_example_image: Addon, docker: DockerAPI
):