diff --git a/homeassistant/components/proxmoxve/coordinator.py b/homeassistant/components/proxmoxve/coordinator.py index 471fcbcc0b2..a42da19bbe4 100644 --- a/homeassistant/components/proxmoxve/coordinator.py +++ b/homeassistant/components/proxmoxve/coordinator.py @@ -244,10 +244,14 @@ class ProxmoxCoordinator(DataUpdateCoordinator[dict[str, ProxmoxNodeData]]): def _async_add_remove_nodes(self, data: dict[str, ProxmoxNodeData]) -> None: """Add new nodes/VMs/containers, track removals.""" current_nodes = set(data.keys()) + self.known_nodes &= current_nodes new_nodes = current_nodes - self.known_nodes if new_nodes: _LOGGER.debug("New nodes found: %s", new_nodes) self.known_nodes.update(new_nodes) + new_node_data = [data[node_name] for node_name in new_nodes] + for nodes_callback in self.new_nodes_callbacks: + nodes_callback(new_node_data) # And yes, track new VM's and containers as well current_vms = { @@ -255,20 +259,34 @@ class ProxmoxCoordinator(DataUpdateCoordinator[dict[str, ProxmoxNodeData]]): for node_name, node_data in data.items() for vmid in node_data.vms } + self.known_vms &= current_vms new_vms = current_vms - self.known_vms if new_vms: _LOGGER.debug("New VMs found: %s", new_vms) self.known_vms.update(new_vms) + new_vm_data = [ + (data[node_name], data[node_name].vms[vmid]) + for node_name, vmid in new_vms + ] + for vms_callback in self.new_vms_callbacks: + vms_callback(new_vm_data) current_containers = { (node_name, vmid) for node_name, node_data in data.items() for vmid in node_data.containers } + self.known_containers &= current_containers new_containers = current_containers - self.known_containers if new_containers: _LOGGER.debug("New containers found: %s", new_containers) self.known_containers.update(new_containers) + new_container_data = [ + (data[node_name], data[node_name].containers[vmid]) + for node_name, vmid in new_containers + ] + for containers_callback in self.new_containers_callbacks: + containers_callback(new_container_data) class ProxmoxSetupError(Exception): diff --git a/tests/components/proxmoxve/test_init.py b/tests/components/proxmoxve/test_init.py index cd2e551593e..66734b827b1 100644 --- a/tests/components/proxmoxve/test_init.py +++ b/tests/components/proxmoxve/test_init.py @@ -37,7 +37,7 @@ from homeassistant.setup import async_setup_component from . import setup_integration -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, async_load_json_array_fixture async def test_config_import( @@ -259,3 +259,69 @@ async def test_migration_v2_to_v3( assert entry.version == 3 assert entry.data[CONF_AUTH_METHOD] == AUTH_PAM assert entry.data[CONF_REALM] == AUTH_PAM + + +async def test_new_vm_creates_entity( + hass: HomeAssistant, + mock_proxmox_client: MagicMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test that a VM appearing after initial load gets an entity created.""" + mock_proxmox_client._node_mock.qemu.get.return_value = [] + await setup_integration(hass, mock_config_entry) + assert mock_config_entry.state == ConfigEntryState.LOADED + + initial_count = len( + er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id) + ) + + mock_proxmox_client._node_mock.qemu.get.return_value = ( + await async_load_json_array_fixture(hass, "nodes/qemu.json", DOMAIN) + ) + + coordinator = mock_config_entry.runtime_data + await coordinator.async_refresh() + await hass.async_block_till_done() + + assert ( + len( + er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + ) + > initial_count + ) + + +async def test_new_container_creates_entity( + hass: HomeAssistant, + mock_proxmox_client: MagicMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test that a container appearing after initial load gets an entity created.""" + mock_proxmox_client._node_mock.lxc.get.return_value = [] + await setup_integration(hass, mock_config_entry) + assert mock_config_entry.state == ConfigEntryState.LOADED + + initial_count = len( + er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id) + ) + + mock_proxmox_client._node_mock.lxc.get.return_value = ( + await async_load_json_array_fixture(hass, "nodes/lxc.json", DOMAIN) + ) + + coordinator = mock_config_entry.runtime_data + await coordinator.async_refresh() + await hass.async_block_till_done() + + assert ( + len( + er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + ) + > initial_count + )