@Override
    protected double maintain() {
        if (!nodeRepository().zone().cloud().dynamicProvisioning()) return 1.0;

        NodeList candidates = nodeRepository().nodes().list()
                                              .parents()
                                              .not().deprovisioning();
        List<CloudAccount> cloudAccounts = candidates.stream()
                                                     .map(Node::cloudAccount)
                                                     .filter(cloudAccount -> !cloudAccount.isUnspecified())
                                                     .distinct()
                                                     .toList();
        Map<String, List<HostEvent>> eventsByHostId = hostProvisioner.hostEventsIn(cloudAccounts).stream()
                                                                     .collect(Collectors.groupingBy(HostEvent::hostId));
        Instant now = nodeRepository().clock().instant();
        for (var host : candidates) {
            List<HostEvent> events = eventsByHostId.get(host.id());
            if (events == null || events.isEmpty()) continue;

            LOG.info("Deprovisioning " + host + " affected by maintenance event" + (events.size() > 1 ? "s" : "") + ": " + events);
            nodeRepository().nodes().deprovision(host.hostname(), Agent.system, now);
        }
        return 1.0;
    }
@Test
    public void retire_hosts() {
        NodeFlavors flavors = FlavorConfigBuilder.createDummies("default");
        MockHostProvisioner hostProvisioner = new MockHostProvisioner(flavors.getFlavors());
        ProvisioningTester tester = new ProvisioningTester.Builder().hostProvisioner(hostProvisioner)
                                                                    .flavors(flavors.getFlavors())
                                                                    .dynamicProvisioning()
                                                                    .build();
        HostRetirer retirer = new HostRetirer(tester.nodeRepository(), Duration.ofDays(1), new MockMetric(), hostProvisioner);
        tester.makeReadyHosts(3, new NodeResources(24, 48, 1000, 10))
              .activateTenantHosts();
        List<String> hostIds = tester.nodeRepository().nodes().list(Node.State.active).mapToList(Node::id);

        // No events scheduled
        retirer.maintain();
        NodeList hosts = tester.nodeRepository().nodes().list();
        assertEquals(0, hosts.deprovisioning().size());

        // Event is scheduled for one known host
        hostProvisioner.addEvent(new HostEvent("event0", hostIds.get(1), getClass().getSimpleName()))
                       .addEvent(new HostEvent("event1", "unknown-host-id", getClass().getSimpleName()));

        // Next run retires host
        retirer.maintain();
        hosts = tester.nodeRepository().nodes().list();
        assertEquals(1, hosts.deprovisioning().size());
    }