@Override
    protected double maintain() {
        List<Node> provisionedSnapshot;
        try {
            NodeList nodes;
            // Host and child nodes are written in separate transactions, but both are written while holding the
            // unallocated lock. Hold the unallocated lock while reading nodes to ensure we get all the children
            // of newly provisioned hosts.
            try (Mutex ignored = nodeRepository().nodes().lockUnallocated()) {
                nodes = nodeRepository().nodes().list();
            }
            provisionedSnapshot = provision(nodes);
        } catch (NodeAllocationException | IllegalStateException e) {
            log.log(Level.WARNING, "Failed to allocate preprovisioned capacity and/or find excess hosts: " + e.getMessage());
            return 0;  // avoid removing excess hosts
        } catch (RuntimeException e) {
            log.log(Level.WARNING, "Failed to allocate preprovisioned capacity and/or find excess hosts", e);
            return 0;  // avoid removing excess hosts
        }

        return markForRemoval(provisionedSnapshot);
    }
@Test
    public void test_minimum_capacity() {
        tester = new DynamicProvisioningTester();
        NodeResources resources1 = new NodeResources(24, 64, 100, 10);
        setPreprovisionCapacityFlag(tester,
                                    new ClusterCapacity(2, resources1.vcpu(), resources1.memoryGiB(), resources1.diskGb(),
                                                        resources1.bandwidthGbps(), resources1.diskSpeed().name(),
                                                        resources1.storageType().name(), resources1.architecture().name(),
                                                        null));
        tester.maintain();

        // Hosts are provisioned
        assertEquals(2, tester.provisionedHostsMatching(resources1));
        assertEquals(0, tester.hostProvisioner.deprovisionedHosts());

        // Next maintenance run does nothing
        tester.assertNodesUnchanged();

        // Pretend shared-host flag has been set to host4's flavor
        var sharedHostNodeResources = new NodeResources(48, 128, 1000, 10, fast, remote);
        tester.hostProvisioner.setHostFlavor("host4");

        // Next maintenance run does nothing
        tester.assertNodesUnchanged();

        // Must be able to allocate 2 nodes with "no resource requirement"
        setPreprovisionCapacityFlag(tester, new ClusterCapacity(2, 0.0, 0.0, 0.0, 0.0, null, null, null, null));

        // Next maintenance run does nothing
        tester.assertNodesUnchanged();

        // Activate hosts
        List<Node> provisioned = tester.nodeRepository.nodes().list().state(Node.State.provisioned).asList();
        tester.provisioningTester.move(Node.State.ready, provisioned);
        tester.provisioningTester.activateTenantHosts();

        // Allocating nodes to a host does not result in provisioning of additional capacity
        ApplicationId application = ProvisioningTester.applicationId();
        NodeResources applicationNodeResources = new NodeResources(4, 8, 50, 0.1);
        tester.provisioningTester.deploy(application,
                                         Capacity.from(new ClusterResources(2, 1, applicationNodeResources)));
        assertEquals(2, tester.nodeRepository.nodes().list().owner(application).size());
        tester.assertNodesUnchanged();

        // Clearing flag does nothing
        setPreprovisionCapacityFlag(tester);
        tester.assertNodesUnchanged();

        // Increasing the capacity provisions additional hosts
        setPreprovisionCapacityFlag(tester, new ClusterCapacity(3, 0.0, 0.0, 0.0, 0.0, null, null, null, null));
        assertEquals(0, tester.provisionedHostsMatching(sharedHostNodeResources));
        assertTrue(node("host102").isEmpty());
        tester.maintain();
        assertEquals(1, tester.provisionedHostsMatching(sharedHostNodeResources));
        assertTrue(node("host102").isPresent());

        // Next maintenance run does nothing
        tester.assertNodesUnchanged();

        // Requiring >0 capacity does nothing as long as it fits on the 3 hosts
        setPreprovisionCapacityFlag(tester,
                                    new ClusterCapacity(3,
                                                        resources1.vcpu() - applicationNodeResources.vcpu(),
                                                        resources1.memoryGiB() - applicationNodeResources.memoryGiB(),
                                                        resources1.diskGb() - applicationNodeResources.diskGb(),
                                                        resources1.bandwidthGbps() - applicationNodeResources.bandwidthGbps(),
                                                        resources1.diskSpeed().name(),
                                                        resources1.storageType().name(),
                                                        resources1.architecture().name(),
                                                        null));
        tester.assertNodesUnchanged();

        // But requiring a bit more in the cluster => provisioning of 2 shared hosts.
        setPreprovisionCapacityFlag(tester,
                                    new ClusterCapacity(3,
                                                        resources1.vcpu() - applicationNodeResources.vcpu() + 1,
                                                        resources1.memoryGiB() - applicationNodeResources.memoryGiB() + 1,
                                                        resources1.diskGb() - applicationNodeResources.diskGb() + 1,
                                                        resources1.bandwidthGbps(),
                                                        resources1.diskSpeed().name(),
                                                        resources1.storageType().name(),
                                                        resources1.architecture().name(),
                                                        null));

        assertEquals(1, tester.provisionedHostsMatching(sharedHostNodeResources));
        assertTrue(node("host102").isPresent());
        assertTrue(node("host103").isEmpty());
        assertTrue(node("host104").isEmpty());
        tester.maintain();
        assertEquals(3, tester.provisionedHostsMatching(sharedHostNodeResources));
        assertTrue(node("host102").isPresent());
        assertTrue(node("host103").isPresent());
        assertTrue(node("host104").isPresent());
    }