Avoid collision when replacing existing config entry with same unique id (#130062)

This commit is contained in:
Erik Montnemery 2024-11-08 07:45:16 +01:00 committed by GitHub
parent e407b4730d
commit 2b7d593ebe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1507,10 +1507,14 @@ class ConfigEntriesFlowManager(
version=result["version"],
)
if existing_entry is not None:
# Unload and remove the existing entry
await self.config_entries._async_remove(existing_entry.entry_id) # noqa: SLF001
await self.config_entries.async_add(entry)
if existing_entry is not None:
await self.config_entries.async_remove(existing_entry.entry_id)
# Clean up devices and entities belonging to the existing entry
self.config_entries._async_clean_up(existing_entry) # noqa: SLF001
result["result"] = entry
return result
@ -1900,7 +1904,21 @@ class ConfigEntries:
self._async_schedule_save()
async def async_remove(self, entry_id: str) -> dict[str, Any]:
"""Remove an entry."""
"""Remove, unload and clean up after an entry."""
unload_success, entry = await self._async_remove(entry_id)
self._async_clean_up(entry)
for discovery_domain in entry.discovery_keys:
async_dispatcher_send_internal(
self.hass,
signal_discovered_config_entry_removed(discovery_domain),
entry,
)
return {"require_restart": not unload_success}
async def _async_remove(self, entry_id: str) -> tuple[bool, ConfigEntry]:
"""Remove and unload an entry."""
if (entry := self.async_get_entry(entry_id)) is None:
raise UnknownEntry
@ -1916,6 +1934,13 @@ class ConfigEntries:
self.async_update_issues()
self._async_schedule_save()
return (unload_success, entry)
@callback
def _async_clean_up(self, entry: ConfigEntry) -> None:
"""Clean up after an entry."""
entry_id = entry.entry_id
dev_reg = device_registry.async_get(self.hass)
ent_reg = entity_registry.async_get(self.hass)
@ -1934,13 +1959,6 @@ class ConfigEntries:
ir.async_delete_issue(self.hass, HOMEASSISTANT_DOMAIN, issue_id)
self._async_dispatch(ConfigEntryChange.REMOVED, entry)
for discovery_domain in entry.discovery_keys:
async_dispatcher_send_internal(
self.hass,
signal_discovered_config_entry_removed(discovery_domain),
entry,
)
return {"require_restart": not unload_success}
@callback
def _async_shutdown(self, event: Event) -> None: