diff options
author | Valerij Fredriksen <valerijf@yahooinc.com> | 2022-11-04 12:10:58 +0100 |
---|---|---|
committer | Valerij Fredriksen <valerijf@yahooinc.com> | 2022-11-04 13:06:18 +0100 |
commit | 67a492188f4cd6482788a38fcfc5a164ac96857d (patch) | |
tree | 825f5622d644941a8271bb581a13a07dd78d09a1 /node-repository | |
parent | 496699607666839c75877ce5686daceb9e1af4e2 (diff) |
Read the node after taking the lock when moving to ready
Diffstat (limited to 'node-repository')
21 files changed, 131 insertions, 145 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java index 230d646699d..084f1f5a9ef 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java @@ -189,29 +189,15 @@ public class Nodes { } } - /** Sets a list of nodes ready and returns the nodes in the ready state */ - public List<Node> setReady(List<Node> nodes, Agent agent, String reason) { - try (Mutex lock = lockUnallocated()) { - List<Node> nodesWithResetFields = nodes.stream() - .map(node -> { - if (node.state() != Node.State.provisioned && node.state() != Node.State.dirty) - illegal("Can not set " + node + " ready. It is not provisioned or dirty."); - if (node.status().wantToDeprovision()) return node; // Do not reset status if wantToDeprovision - return node.withWantToRetire(false, - false, - false, - Agent.system, - clock.instant()); - }) - .collect(Collectors.toList()); - return db.writeTo(Node.State.ready, nodesWithResetFields, agent, Optional.of(reason)); - } - } + /** Sets a node to ready and returns the node in the ready state */ + public Node setReady(NodeMutex nodeMutex, Agent agent, String reason) { + Node node = nodeMutex.node(); + if (node.state() != Node.State.provisioned && node.state() != Node.State.dirty) + illegal("Can not set " + node + " ready. It is not provisioned or dirty."); + if (!node.status().wantToDeprovision()) // Do not reset status if wantToDeprovision + node = node.withWantToRetire(false, false, false, agent, clock.instant()); - public Node setReady(String hostname, Agent agent, String reason) { - Node nodeToReady = requireNode(hostname); - if (nodeToReady.state() == Node.State.ready) return nodeToReady; - return setReady(List.of(nodeToReady), agent, reason).get(0); + return db.writeTo(Node.State.ready, node, agent, Optional.of(reason)); } /** Reserve nodes. This method does <b>not</b> lock the node repository. */ @@ -475,21 +461,27 @@ public class Nodes { * containers this will remove the node from node repository, otherwise the node will be moved to state ready. */ public Node markNodeAvailableForNewAllocation(String hostname, Agent agent, String reason) { - Node node = requireNode(hostname); - if (node.flavor().getType() == Flavor.Type.DOCKER_CONTAINER && node.type() == NodeType.tenant) { - if (node.state() != Node.State.dirty) - illegal("Cannot make " + node + " available for new allocation as it is not in state [dirty]"); - return removeRecursively(node, true).get(0); - } + try (NodeMutex nodeMutex = lockAndGetRequired(hostname)) { + Node node = nodeMutex.node(); + if (node.type() == NodeType.tenant) { + if (node.state() != Node.State.dirty) + illegal("Cannot make " + node + " available for new allocation as it is not in state [dirty]"); + + NestedTransaction transaction = new NestedTransaction(); + db.removeNodes(List.of(node), transaction); + transaction.commit(); + return node; + } - if (node.state() == Node.State.ready) return node; + if (node.state() == Node.State.ready) return node; - Node parentHost = node.parentHostname().flatMap(this::node).orElse(node); - List<String> failureReasons = NodeFailer.reasonsToFailHost(parentHost); - if ( ! failureReasons.isEmpty()) - illegal(node + " cannot be readied because it has hard failures: " + failureReasons); + Node parentHost = node.parentHostname().flatMap(this::node).orElse(node); + List<String> failureReasons = NodeFailer.reasonsToFailHost(parentHost); + if (!failureReasons.isEmpty()) + illegal(node + " cannot be readied because it has hard failures: " + failureReasons); - return setReady(List.of(node), agent, reason).get(0); + return setReady(nodeMutex, agent, reason); + } } /** diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java index 26e1cd71a3d..dccfa830a8d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java @@ -23,6 +23,7 @@ import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.curator.mock.MockCurator; import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.hosted.provision.Node; +import com.yahoo.vespa.hosted.provision.NodeMutex; import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.applications.Application; import com.yahoo.vespa.hosted.provision.applications.Cluster; @@ -148,7 +149,7 @@ public class MockNodeRepository extends NodeRepository { nodes.remove(node7); nodes.remove(node55); nodes = nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + nodes.forEach(node -> nodes().setReady(new NodeMutex(node, () -> {}), Agent.system, getClass().getSimpleName())); nodes().fail(node5.hostname(), Agent.system, getClass().getSimpleName()); nodes().deallocateRecursively(node55.hostname(), Agent.system, getClass().getSimpleName()); @@ -195,7 +196,7 @@ public class MockNodeRepository extends NodeRepository { largeNodes.add(Node.create("node13", ipConfig(13), "host13.yahoo.com", resources(10, 48, 500, 1, fast, local), NodeType.tenant).build()); largeNodes.add(Node.create("node14", ipConfig(14), "host14.yahoo.com", resources(10, 48, 500, 1, fast, local), NodeType.tenant).build()); nodes().addNodes(largeNodes, Agent.system); - nodes().setReady(largeNodes, Agent.system, getClass().getSimpleName()); + largeNodes.forEach(node -> nodes().setReady(new NodeMutex(node, () -> {}), Agent.system, getClass().getSimpleName())); ApplicationId app4 = ApplicationId.from(TenantName.from("tenant4"), ApplicationName.from("application4"), InstanceName.from("instance4")); ClusterSpec cluster4 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("id4")).vespaVersion("6.42").build(); activate(provisioner.prepare(app4, cluster4, Capacity.from(new ClusterResources(2, 1, new NodeResources(10, 48, 500, 1)), false, true), null), app4, provisioner); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java index b338527b0fd..0a179babc10 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java @@ -60,7 +60,7 @@ public class NodeRepositoryTest { // Expected } - tester.nodeRepository().nodes().setReady("host1", Agent.system, getClass().getSimpleName()); + tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().lockAndGetRequired("host1"), Agent.system, getClass().getSimpleName()); tester.nodeRepository().nodes().removeRecursively("host1"); } @@ -85,8 +85,8 @@ public class NodeRepositoryTest { @Test public void fail_readying_with_hard_fail() { NodeRepositoryTester tester = new NodeRepositoryTester(); - tester.addHost("host1", "host1", "default", NodeType.tenant); - tester.addHost("host2", "host2", "default", NodeType.tenant); + tester.addHost("host1", "host1", "default", NodeType.host); + tester.addHost("host2", "host2", "default", NodeType.host); Node node2 = tester.nodeRepository().nodes().node("host2").orElseThrow(); var reportsBuilder = new Reports.Builder(node2.reports()); @@ -133,7 +133,7 @@ public class NodeRepositoryTest { // Now node10 is in provisioned, set node11 to failed and node12 to ready, and it should be OK to delete host1 tester.nodeRepository().nodes().fail("node11", Agent.system, getClass().getSimpleName()); - tester.nodeRepository().nodes().setReady("node12", Agent.system, getClass().getSimpleName()); + tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().lockAndGetRequired("node12"), Agent.system, getClass().getSimpleName()); tester.nodeRepository().nodes().removeRecursively("node12"); // Remove one of the children first instead assertEquals(4, tester.nodeRepository().nodes().list().size()); tester.nodeRepository().nodes().removeRecursively("host1"); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java index 65a57ebd53e..cd73914850d 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java @@ -4,7 +4,6 @@ package com.yahoo.vespa.hosted.provision; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.Flavor; import com.yahoo.config.provision.NodeFlavors; -import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.Zone; import com.yahoo.config.provisioning.FlavorsConfig; @@ -68,10 +67,6 @@ public class NodeRepositoryTester { return addNode(id, hostname, null, nodeFlavors.getFlavorOrThrow(flavor), type); } - public Node addNode(String id, String parentHostname, NodeResources resources) { - return addNode(id, id, parentHostname, new Flavor(resources), NodeType.tenant); - } - public Node addNode(String id, String hostname, String parentHostname, String flavor, NodeType type) { return addNode(id, hostname, parentHostname, nodeFlavors.getFlavorOrThrow(flavor), type); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java index 393b25a78da..917e49bc561 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java @@ -18,7 +18,6 @@ import com.yahoo.vespa.hosted.provision.Nodelike; import com.yahoo.vespa.hosted.provision.applications.Application; import com.yahoo.vespa.hosted.provision.applications.Cluster; import com.yahoo.vespa.hosted.provision.applications.ScalingEvent; -import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.provisioning.CapacityPolicies; import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator; @@ -108,7 +107,7 @@ class AutoscalingTester { Node host = nodeRepository().nodes().node(node.parentHostname().get()).get(); host = host.with(new IP.Config(Set.of("::" + 0 + ":0"), Set.of("::" + 0 + ":2"))); if (host.state() == Node.State.provisioned) - nodeRepository().nodes().setReady(List.of(host), Agent.system, getClass().getSimpleName()); + provisioningTester.move(Node.State.ready, host); } public void deactivateRetired(ApplicationId application, ClusterSpec cluster, Capacity capacity) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java index 660a84e6c15..59080f60982 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java @@ -313,7 +313,7 @@ public class FailedExpirerTest { .map(this::get) .collect(Collectors.toList()); nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + tester.move(Node.State.ready, nodes); return this; } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java index 65280e9edc8..30b44d713a3 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java @@ -297,7 +297,7 @@ public class HostCapacityMaintainerTest { // Activate hosts List<Node> provisioned = tester.nodeRepository.nodes().list().state(Node.State.provisioned).asList(); - tester.nodeRepository.nodes().setReady(provisioned, Agent.system, this.getClass().getSimpleName()); + tester.provisioningTester.move(Node.State.ready, provisioned); tester.provisioningTester.activateTenantHosts(); // Allocating nodes to a host does not result in provisioning of additional capacity @@ -477,7 +477,7 @@ public class HostCapacityMaintainerTest { dynamicProvisioningTester.maintain(); List<ProvisionedHost> newHosts = dynamicProvisioningTester.hostProvisioner.provisionedHosts(); assertEquals(1, newHosts.size()); - tester.nodeRepository().nodes().setReady(newHosts.get(0).hostHostname(), Agent.operator, getClass().getSimpleName()); + tester.move(Node.State.ready, newHosts.get(0).hostHostname()); tester.prepareAndActivateInfraApplication(hostApp, hostType); assertEquals(3, tester.nodeRepository().nodes().list(Node.State.active).nodeType(hostType).size()); @@ -573,7 +573,7 @@ public class HostCapacityMaintainerTest { .toList(); assertEquals(count, provisionedHostnames.size()); for (var hostname : provisionedHostnames) { - tester.provisioningTester.nodeRepository().nodes().setReady(hostname, Agent.operator, getClass().getSimpleName()); + tester.provisioningTester.move(Node.State.ready, hostname); } tester.provisioningTester.prepareAndActivateInfraApplication(DynamicProvisioningTester.tenantHostApp.getApplicationId(), NodeType.host); NodeList activeHosts = tester.provisioningTester.nodeRepository().nodes() diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java index 5211b855fff..0d1d138276a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java @@ -75,7 +75,7 @@ public class InactiveAndFailedExpirerTest { assertEquals(2, dirty.size()); // One node is set back to ready - Node ready = tester.nodeRepository().nodes().setReady(List.of(dirty.asList().get(0)), Agent.system, getClass().getSimpleName()).get(0); + Node ready = tester.move(Node.State.ready, dirty.asList().get(0)); assertEquals("Allocated history is removed on readying", List.of(History.Event.Type.provisioned, History.Event.Type.readied), ready.history().events().stream().map(History.Event::type).collect(Collectors.toList())); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java index 2204719aaf0..a80cb910c29 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java @@ -59,7 +59,7 @@ public class LoadBalancerExpirerTest { assertNotSame(LoadBalancer.State.inactive, loadBalancers.get().get(lb2).state()); // Expirer defers removal while nodes are still allocated to application - tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().list(Node.State.dirty).asList(), Agent.system, getClass().getSimpleName()); + tester.move(Node.State.ready, tester.nodeRepository().nodes().list(Node.State.dirty).asList()); expirer.maintain(); assertEquals(Set.of(), tester.loadBalancerService().instances().get(lb1).reals()); assertEquals(Set.of(), loadBalancers.get().get(lb1).instance().get().reals()); @@ -138,7 +138,7 @@ public class LoadBalancerExpirerTest { .cluster(cluster) .asList(); nodes = tester.nodeRepository().nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); - tester.nodeRepository().nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + tester.move(Node.State.ready, nodes); } private void deployApplication(ApplicationId application, ClusterSpec.Id... clusters) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java index 03a6a11d4bd..77dbc86769f 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java @@ -181,7 +181,7 @@ public class MetricsReporterTest { nodeFlavors.getFlavorOrThrow("host"), NodeType.host).build(); nodeRepository.nodes().addNodes(List.of(dockerHost), Agent.system); nodeRepository.nodes().deallocateRecursively("dockerHost", Agent.system, getClass().getSimpleName()); - nodeRepository.nodes().setReady("dockerHost", Agent.system, getClass().getSimpleName()); + tester.move(Node.State.ready, "dockerHost"); Node container1 = Node.reserve(Set.of("::2"), "container1", "dockerHost", new NodeResources(1, 3, 2, 1), NodeType.tenant).build(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java index 977d72c11ea..1b0826a8323 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java @@ -253,7 +253,7 @@ public class NodeFailTester { nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); - return nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + return tester.move(Node.State.ready, nodes); } private List<Node> createHostNodes(int count) { @@ -262,7 +262,7 @@ public class NodeFailTester { Optional.empty(), NodeType.host, 10, false); nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); tester.activateTenantHosts(); - return nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + return tester.move(Node.State.ready, nodes); } // Prefer using this instead of the above diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java index b9021bff3c3..5bdff2d3a3a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java @@ -19,7 +19,6 @@ import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeList; import com.yahoo.vespa.hosted.provision.NodeRepository; -import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder; import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester; import com.yahoo.vespa.hosted.provision.testutils.MockDeployer; @@ -97,7 +96,7 @@ public class RebalancerTest { assertTrue("Want to retire is reset", tester.getNodes(Node.State.active).stream().noneMatch(node -> node.status().wantToRetire())); assertEquals("Reserved node was moved to dirty", 2, tester.getNodes(Node.State.dirty).size()); String reservedHostname = tester.getNodes(Node.State.dirty).owner(memoryApp).first().get().hostname(); - tester.nodeRepository().nodes().setReady(reservedHostname, Agent.system, "Cleanup"); + tester.tester.move(Node.State.ready, reservedHostname); tester.nodeRepository().nodes().removeRecursively(reservedHostname); // ... otherwise we successfully rebalance, again reducing skew diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java index 3d7bc154c52..f5e524a90cc 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java @@ -244,7 +244,7 @@ public class RetiredExpirerTest { var nodes = List.of(node); nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + tester.move(Node.State.ready, nodes); // no changes while replacement config server is ready retiredExpirer.run(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java index 259277925f4..8e3932e51a8 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java @@ -613,7 +613,7 @@ public class OsVersionsTest { Node newNode = Node.create(node.id(), node.ipConfig(), node.hostname(), node.flavor(), node.type()) .build(); node = tester.nodeRepository().nodes().addNodes(List.of(newNode), Agent.system).get(0); - node = tester.nodeRepository().nodes().setReady(node.hostname(), Agent.system, getClass().getSimpleName()); + node = tester.move(Node.State.ready, node); tester.prepareAndActivateInfraApplication(application, nodeType); node = tester.nodeRepository().nodes().node(node.hostname()).get(); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java index 0c321159748..1645da70bc1 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicProvisioningTest.java @@ -475,7 +475,7 @@ public class DynamicProvisioningTest { List<HostSpec> prepared = tester.prepare(application, clusterSpec, nodes, groups, resources); NodeList provisionedHosts = tester.nodeRepository().nodes().list(Node.State.provisioned).nodeType(NodeType.host); if (!provisionedHosts.isEmpty()) { - tester.nodeRepository().nodes().setReady(provisionedHosts.asList(), Agent.system, DynamicProvisioningTest.class.getSimpleName()); + tester.move(Node.State.ready, provisionedHosts.asList()); tester.activateTenantHosts(); } tester.activate(application, prepared); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java index 45b5d9020d4..471fabb1206 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java @@ -24,7 +24,6 @@ import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeList; -import com.yahoo.vespa.hosted.provision.NodeMutex; import com.yahoo.vespa.hosted.provision.maintenance.ReservationExpirer; import com.yahoo.vespa.hosted.provision.maintenance.TestMetric; import com.yahoo.vespa.hosted.provision.node.Agent; @@ -133,7 +132,7 @@ public class ProvisioningTest { tester.activate(application2, state2App2.allHosts); // deploy first app again - tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().list(Node.State.dirty).asList(), Agent.system, "recycled"); + tester.move(Node.State.ready, tester.nodeRepository().nodes().list(Node.State.dirty).asList()); SystemState state7 = prepare(application1, 2, 2, 3, 3, defaultResources, tester); state7.assertEquals(state1); tester.activate(application1, state7.allHosts); @@ -924,7 +923,7 @@ public class ProvisioningTest { Node.create("cfghost2", new IP.Config(Set.of("::2:0"), Set.of("::2:1")), "cfghost2", flavor, NodeType.confighost).ipConfig(IP.Config.of(Set.of("::2:0"), Set.of("::2:1"), List.of())).build(), Node.create("cfg1", new IP.Config(Set.of("::1:1"), Set.of()), "cfg1", flavor, NodeType.config).parentHostname("cfghost1").build(), Node.create("cfg2", new IP.Config(Set.of("::2:1"), Set.of()), "cfg2", flavor, NodeType.config).parentHostname("cfghost2").build()); - tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().addNodes(nodes, Agent.system), Agent.system, ProvisioningTest.class.getSimpleName()); + tester.move(Node.State.ready, tester.nodeRepository().nodes().addNodes(nodes, Agent.system)); InfraApplication cfgHostApp = new ConfigServerHostApplication(); InfraApplication cfgApp = new ConfigServerApplication(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java index 8affe516fa9..949ed8ffbcb 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java @@ -467,7 +467,7 @@ public class ProvisioningTester { nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + move(Node.State.ready, nodes); ConfigServerApplication application = new ConfigServerApplication(); List<HostSpec> hosts = prepare(application.getApplicationId(), @@ -494,7 +494,7 @@ public class ProvisioningTester { List<Node> nodes = makeProvisionedNodes(n, flavor, reservedTo, type, ipAddressPoolSize, dualStack); nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); nodes.forEach(node -> { if (node.resources().isUnspecified()) throw new IllegalArgumentException(); }); - return nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); + return move(Node.State.ready, nodes); } public Flavor asFlavor(String flavorString, NodeType type) { @@ -536,8 +536,7 @@ public class ProvisioningTester { } nodes = nodeRepository.nodes().addNodes(nodes, Agent.system); nodes = nodeRepository.nodes().deallocate(nodes, Agent.system, getClass().getSimpleName()); - nodeRepository.nodes().setReady(nodes, Agent.system, getClass().getSimpleName()); - return nodes; + return move(Node.State.ready, nodes); } /** Create one or more child nodes on given parent host */ @@ -614,6 +613,16 @@ public class ProvisioningTester { .count(); } + public Node move(Node.State toState, String hostname) { + return move(toState, nodeRepository.nodes().node(hostname).orElseThrow()); + } + public Node move(Node.State toState, Node node) { + return move(toState, List.of(node)).get(0); + } + public List<Node> move(Node.State toState, List<Node> nodes) { + return nodeRepository.database().writeTo(toState, nodes, Agent.operator, Optional.of("ProvisionTester")); + } + public static final class Builder { private Curator curator; diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java index aaef785704d..5143aa91f56 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java @@ -12,9 +12,9 @@ import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.Flavor; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; +import com.yahoo.config.provision.NodeAllocationException; import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.NodeType; -import com.yahoo.config.provision.NodeAllocationException; import com.yahoo.config.provision.ProvisionLock; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; @@ -23,7 +23,6 @@ import com.yahoo.config.provision.Zone; import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeList; -import com.yahoo.vespa.hosted.provision.node.Agent; import org.junit.Test; import java.util.HashSet; @@ -82,7 +81,7 @@ public class VirtualNodeProvisioningTest { // The surplus node is dirtied and then readied for new allocations List<Node> dirtyNode = tester.nodeRepository().nodes().list(Node.State.dirty).owner(applicationId).asList(); assertEquals(1, dirtyNode.size()); - tester.nodeRepository().nodes().setReady(dirtyNode, Agent.system, getClass().getSimpleName()); + tester.move(Node.State.ready, dirtyNode); // Go up to 4 nodes again in container cluster List<HostSpec> containerHosts3 = tester.prepare(applicationId, containerClusterSpec, containerNodeCount, groups, resources1); @@ -648,7 +647,7 @@ public class VirtualNodeProvisioningTest { else { assertEquals(0, tester.getNodes(app1, Node.State.inactive).size()); assertEquals(2, tester.nodeRepository().nodes().list(Node.State.dirty).size()); - tester.nodeRepository().nodes().setReady(tester.nodeRepository().nodes().list(Node.State.dirty).asList(), Agent.system, "test"); + tester.move(Node.State.ready, tester.nodeRepository().nodes().list(Node.State.dirty).asList()); tester.activate(app1, cluster1, Capacity.from(new ClusterResources(4, 1, r))); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java index 903b6022bd2..a9179427210 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java @@ -92,10 +92,10 @@ public class NodesV2ApiTest { // POST new nodes assertResponse(new Request("http://localhost:8080/nodes/v2/node", - ("[" + asNodeJson("host8.yahoo.com", "default", "127.0.8.1") + "," + // test with only 1 ip address - asHostJson("host9.yahoo.com", "large-variant", List.of("node9-1.yahoo.com"), "127.0.9.1", "::9:1") + "," + + ("[" + asHostJson("host8.yahoo.com", "default", List.of("127.0.8.2"), List.of(), "127.0.8.1") + "," + // test with only 1 ip address + asHostJson("host9.yahoo.com", "large-variant", List.of(), List.of("node9-1.yahoo.com"), "127.0.9.1", "::9:1") + "," + asNodeJson("parent2.yahoo.com", NodeType.host, "large-variant", Optional.of(TenantName.from("myTenant")), - Optional.of(ApplicationId.from("tenant1", "app1", "instance1")), Optional.empty(), List.of(), "127.0.127.1", "::127:1") + "," + + Optional.of(ApplicationId.from("tenant1", "app1", "instance1")), Optional.empty(), List.of(), List.of(), "127.0.127.1", "::127:1") + "," + asDockerNodeJson("host11.yahoo.com", "parent.host.yahoo.com", "::11") + "]"). getBytes(StandardCharsets.UTF_8), Request.Method.POST), @@ -141,11 +141,6 @@ public class NodesV2ApiTest { new byte[0], Request.Method.PUT), "{\"message\":\"Moved host2.yahoo.com to active\"}"); - // Delete a ready node - assertResponse(new Request("http://localhost:8080/nodes/v2/node/host8.yahoo.com", - new byte[0], Request.Method.DELETE), - "{\"message\":\"Removed host8.yahoo.com\"}"); - // or, PUT a node in failed ... assertResponse(new Request("http://localhost:8080/nodes/v2/state/failed/test-node-pool-102-2", new byte[0], Request.Method.PUT), @@ -331,7 +326,7 @@ public class NodesV2ApiTest { // Attempt to POST host node with already assigned IP tester.assertResponse(new Request("http://localhost:8080/nodes/v2/node", - "[" + asHostJson("host200.yahoo.com", "default", List.of(), "127.0.2.1") + "]", + "[" + asHostJson("host200.yahoo.com", "default", List.of(), List.of(), "127.0.2.1") + "]", Request.Method.POST), 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Cannot assign [127.0.2.1] to host200.yahoo.com: [127.0.2.1] already assigned to host2.yahoo.com\"}"); @@ -343,7 +338,7 @@ public class NodesV2ApiTest { // Node types running a single container can share their IP address with child node tester.assertResponse(new Request("http://localhost:8080/nodes/v2/node", - "[" + asNodeJson("cfghost42.yahoo.com", NodeType.confighost, "default", Optional.empty(), Optional.empty(), Optional.empty(), List.of(), "127.0.42.1") + "]", + "[" + asNodeJson("cfghost42.yahoo.com", NodeType.confighost, "default", Optional.empty(), Optional.empty(), Optional.empty(), List.of(), List.of(), "127.0.42.1") + "]", Request.Method.POST), 200, "{\"message\":\"Added 1 nodes to the provisioned state\"}"); tester.assertResponse(new Request("http://localhost:8080/nodes/v2/node", @@ -359,7 +354,7 @@ public class NodesV2ApiTest { // ... nor with child node on different host tester.assertResponse(new Request("http://localhost:8080/nodes/v2/node", - "[" + asNodeJson("cfghost43.yahoo.com", NodeType.confighost, "default", Optional.empty(), Optional.empty(), Optional.empty(), List.of(), "127.0.43.1") + "]", + "[" + asNodeJson("cfghost43.yahoo.com", NodeType.confighost, "default", Optional.empty(), Optional.empty(), Optional.empty(), List.of(), List.of(), "127.0.43.1") + "]", Request.Method.POST), 200, "{\"message\":\"Added 1 nodes to the provisioned state\"}"); tester.assertResponse(new Request("http://localhost:8080/nodes/v2/node/cfg42.yahoo.com", @@ -401,7 +396,7 @@ public class NodesV2ApiTest { @Test public void fails_to_ready_node_with_hard_fail() throws Exception { assertResponse(new Request("http://localhost:8080/nodes/v2/node", - ("[" + asHostJson("host12.yahoo.com", "default", List.of()) + "]"). + ("[" + asHostJson("host12.yahoo.com", "default", List.of(), List.of()) + "]"). getBytes(StandardCharsets.UTF_8), Request.Method.POST), "{\"message\":\"Added 1 nodes to the provisioned state\"}"); @@ -440,18 +435,7 @@ public class NodesV2ApiTest { @Test public void acl_request_by_tenant_node() throws Exception { - String hostname = "foo.yahoo.com"; - assertResponse(new Request("http://localhost:8080/nodes/v2/node", - ("[" + asNodeJson(hostname, "default", "127.0.222.1") + "]").getBytes(StandardCharsets.UTF_8), - Request.Method.POST), - "{\"message\":\"Added 1 nodes to the provisioned state\"}"); - assertResponse(new Request("http://localhost:8080/nodes/v2/state/dirty/" + hostname, - new byte[0], Request.Method.PUT), - "{\"message\":\"Moved foo.yahoo.com to dirty\"}"); - assertResponse(new Request("http://localhost:8080/nodes/v2/state/ready/" + hostname, - new byte[0], Request.Method.PUT), - "{\"message\":\"Moved foo.yahoo.com to ready\"}"); - assertFile(new Request("http://localhost:8080/nodes/v2/acl/" + hostname), "acl-tenant-node.json"); + assertFile(new Request("http://localhost:8080/nodes/v2/acl/host3.yahoo.com"), "acl-tenant-node.json"); } @Test @@ -962,7 +946,7 @@ public class NodesV2ApiTest { String hostname = "host42.yahoo.com"; // Add host with switch hostname String json = asNodeJson(hostname, NodeType.host, "default", Optional.empty(), Optional.empty(), - Optional.of("switch0"), List.of(), "127.0.42.1", "::42:1"); + Optional.of("switch0"), List.of(), List.of(), "127.0.42.1", "::42:1"); assertResponse(new Request("http://localhost:8080/nodes/v2/node", ("[" + json + "]").getBytes(StandardCharsets.UTF_8), Request.Method.POST), @@ -1055,22 +1039,22 @@ public class NodesV2ApiTest { "\"flavor\":\"" + flavor + "\"}"; } - private static String asHostJson(String hostname, String flavor, List<String> additionalHostnames, String... ipAddress) { + private static String asHostJson(String hostname, String flavor, List<String> additionalIpAddresses, List<String> additionalHostnames, String... ipAddress) { return asNodeJson(hostname, NodeType.host, flavor, Optional.empty(), Optional.empty(), Optional.empty(), - additionalHostnames, ipAddress); + additionalIpAddresses, additionalHostnames, ipAddress); } private static String asNodeJson(String hostname, NodeType nodeType, String flavor, Optional<TenantName> reservedTo, Optional<ApplicationId> exclusiveTo, Optional<String> switchHostname, - List<String> additionalHostnames, String... ipAddress) { + List<String> additionalIpAddresses, List<String> additionalHostnames, String... ipAddress) { return "{\"hostname\":\"" + hostname + "\", \"id\":\"" + hostname + "\"," + createIpAddresses(ipAddress) + "\"flavor\":\"" + flavor + "\"" + (reservedTo.map(tenantName -> ", \"reservedTo\":\"" + tenantName.value() + "\"").orElse("")) + (exclusiveTo.map(appId -> ", \"exclusiveTo\":\"" + appId.serializedForm() + "\"").orElse("")) + (switchHostname.map(s -> ", \"switchHostname\":\"" + s + "\"").orElse("")) + - (additionalHostnames.isEmpty() ? "" : ", \"additionalHostnames\":[\"" + - String.join("\",\"", additionalHostnames) + "\"]") + + (additionalIpAddresses.isEmpty() ? "" : ", \"additionalIpAddresses\":[\"" + String.join("\",\"", additionalIpAddresses) + "\"]") + + (additionalHostnames.isEmpty() ? "" : ", \"additionalHostnames\":[\"" + String.join("\",\"", additionalHostnames) + "\"]") + ", \"type\":\"" + nodeType + "\"}"; } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/acl-tenant-node.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/acl-tenant-node.json index 16cf5c36dcc..7b3af112a44 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/acl-tenant-node.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/acl-tenant-node.json @@ -4,176 +4,170 @@ "hostname": "cfg1.yahoo.com", "type": "config", "ipAddress": "127.0.201.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "cfg1.yahoo.com", "type": "config", "ipAddress": "::201:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "cfg2.yahoo.com", "type": "config", "ipAddress": "127.0.202.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "cfg2.yahoo.com", "type": "config", "ipAddress": "::202:1", - "trustedBy": "foo.yahoo.com" - }, - { - "hostname": "foo.yahoo.com", - "type": "tenant", - "ipAddress": "127.0.222.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host1.yahoo.com", "type": "tenant", "ipAddress": "127.0.1.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host1.yahoo.com", "type": "tenant", "ipAddress": "::1:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host10.yahoo.com", "type": "tenant", "ipAddress": "127.0.10.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host10.yahoo.com", "type": "tenant", "ipAddress": "::10:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host13.yahoo.com", "type": "tenant", "ipAddress": "127.0.13.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host13.yahoo.com", "type": "tenant", "ipAddress": "::13:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host14.yahoo.com", "type": "tenant", "ipAddress": "127.0.14.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host14.yahoo.com", "type": "tenant", "ipAddress": "::14:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host2.yahoo.com", "type": "tenant", "ipAddress": "127.0.2.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host2.yahoo.com", "type": "tenant", "ipAddress": "::2:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host3.yahoo.com", "type": "tenant", "ipAddress": "127.0.3.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host3.yahoo.com", "type": "tenant", "ipAddress": "::3:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host4.yahoo.com", "type": "tenant", "ipAddress": "127.0.4.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host4.yahoo.com", "type": "tenant", "ipAddress": "::4:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host5.yahoo.com", "type": "tenant", "ipAddress": "127.0.5.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host5.yahoo.com", "type": "tenant", "ipAddress": "::5:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host55.yahoo.com", "type": "tenant", "ipAddress": "127.0.55.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host55.yahoo.com", "type": "tenant", "ipAddress": "::55:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host6.yahoo.com", "type": "tenant", "ipAddress": "127.0.6.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host6.yahoo.com", "type": "tenant", "ipAddress": "::6:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host7.yahoo.com", "type": "tenant", "ipAddress": "127.0.7.1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "host7.yahoo.com", "type": "tenant", "ipAddress": "::7:1", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" }, { "hostname": "test-node-pool-102-2", "type": "tenant", "ipAddress": "::102:2", - "trustedBy": "foo.yahoo.com" + "trustedBy": "host3.yahoo.com" } ], "trustedNetworks": [], "trustedPorts": [ { - "port":22, - "trustedBy":"foo.yahoo.com" + "port": 22, + "trustedBy": "host3.yahoo.com" } ] } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json index 7df4cb042a1..f6d7a9e201c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json @@ -2,15 +2,32 @@ "url": "http://localhost:8080/nodes/v2/node/host8.yahoo.com", "id": "host8.yahoo.com", "state": "provisioned", - "type": "tenant", + "type": "host", "hostname": "host8.yahoo.com", "flavor": "default", "cpuCores": 2.0, - "resources":{"vcpu":2.0,"memoryGb":16.0,"diskGb":400.0,"bandwidthGbps":10.0,"diskSpeed":"fast","storageType": "remote","architecture":"x86_64"}, - "realResources":{"vcpu":2.0,"memoryGb":16.0,"diskGb":400.0,"bandwidthGbps":10.0,"diskSpeed":"fast","storageType": "remote","architecture":"x86_64"}, + "resources": { + "vcpu": 2.0, + "memoryGb": 16.0, + "diskGb": 400.0, + "bandwidthGbps": 10.0, + "diskSpeed": "fast", + "storageType": "remote", + "architecture": "x86_64" + }, + "realResources": { + "vcpu": 2.0, + "memoryGb": 16.0, + "diskGb": 400.0, + "bandwidthGbps": 10.0, + "diskSpeed": "fast", + "storageType": "remote", + "architecture": "x86_64" + }, "environment": "BARE_METAL", "rebootGeneration": 0, "currentRebootGeneration": 0, + "deferOsUpgrade": false, "failCount": 0, "wantToRetire": false, "preferToRetire": false, @@ -31,8 +48,6 @@ "agent": "operator" } ], - "ipAddresses": [ - "127.0.8.1" - ], - "additionalIpAddresses": [] + "ipAddresses": ["127.0.8.1"], + "additionalIpAddresses": ["127.0.8.2"] } |