use of com.yahoo.vespa.hosted.provision.Node in project vespa by vespa-engine.
the class SerializationTest method want_to_retire_defaults_to_false.
@Test
public void want_to_retire_defaults_to_false() {
String nodeData = "{\n" + " \"type\" : \"tenant\",\n" + " \"flavor\" : \"large\",\n" + " \"openStackId\" : \"myId\",\n" + " \"hostname\" : \"myHostname\",\n" + " \"ipAddresses\" : [\"127.0.0.1\"]\n" + "}";
Node node = nodeSerializer.fromJson(State.provisioned, Utf8.toBytes(nodeData));
assertFalse(node.status().wantToRetire());
}
use of com.yahoo.vespa.hosted.provision.Node in project vespa by vespa-engine.
the class SerializationTest method testRetiredNodeSerialization.
@Test
public void testRetiredNodeSerialization() {
Node node = createNode();
clock.advance(Duration.ofMinutes(3));
assertEquals(0, node.history().events().size());
node = node.allocate(ApplicationId.from(TenantName.from("myTenant"), ApplicationName.from("myApplication"), InstanceName.from("myInstance")), ClusterMembership.from("content/myId/0/0", Vtag.currentVersion), clock.instant());
assertEquals(1, node.history().events().size());
clock.advance(Duration.ofMinutes(2));
node = node.retire(Agent.application, clock.instant());
Node copy = nodeSerializer.fromJson(Node.State.provisioned, nodeSerializer.toJson(node));
assertEquals(2, copy.history().events().size());
assertEquals(clock.instant(), copy.history().event(History.Event.Type.retired).get().at());
assertEquals(Agent.application, (copy.history().event(History.Event.Type.retired).get()).agent());
assertTrue(copy.allocation().get().membership().retired());
Node removable = copy.with(node.allocation().get().removable());
Node removableCopy = nodeSerializer.fromJson(Node.State.provisioned, nodeSerializer.toJson(removable));
assertTrue(removableCopy.allocation().get().isRemovable());
}
use of com.yahoo.vespa.hosted.provision.Node in project vespa by vespa-engine.
the class SerializationTest method serialize_additional_ip_addresses.
@Test
public void serialize_additional_ip_addresses() throws IOException {
Node node = createNode();
// Test round-trip with additional addresses
node = node.withAdditionalIpAddresses(ImmutableSet.of("10.0.0.1", "10.0.0.2", "10.0.0.3"));
Node copy = nodeSerializer.fromJson(node.state(), nodeSerializer.toJson(node));
assertEquals(node.additionalIpAddresses(), copy.additionalIpAddresses());
// Test round-trip without additional addresses (handle empty ip set)
node = createNode();
copy = nodeSerializer.fromJson(node.state(), nodeSerializer.toJson(node));
assertEquals(node.additionalIpAddresses(), copy.additionalIpAddresses());
// TODO remove after MAI 2017
// Test deserialization of a json file without the additional ip addresses field
String json = "{\n" + " \"url\": \"http://localhost:8080/nodes/v2/node/host1.yahoo.com\",\n" + " \"id\": \"host1.yahoo.com\",\n" + " \"state\": \"active\",\n" + " \"type\": \"tenant\",\n" + " \"hostname\": \"host1.yahoo.com\",\n" + " \"openStackId\": \"node1\",\n" + " \"flavor\": \"default\",\n" + " \"canonicalFlavor\": \"default\",\n" + " \"minDiskAvailableGb\":400.0,\n" + " \"minMainMemoryAvailableGb\":16.0,\n" + " \"description\":\"Flavor-name-is-default\",\n" + " \"minCpuCores\":2.0,\n" + " \"environment\":\"BARE_METAL\",\n" + " \"owner\": {\n" + " \"tenant\": \"tenant2\",\n" + " \"application\": \"application2\",\n" + " \"instance\": \"instance2\"\n" + " },\n" + " \"membership\": {\n" + " \"clustertype\": \"content\",\n" + " \"clusterid\": \"id2\",\n" + " \"group\": \"0\",\n" + " \"index\": 0,\n" + " \"retired\": false\n" + " },\n" + " \"restartGeneration\": 0,\n" + " \"currentRestartGeneration\": 0,\n" + " \"wantedDockerImage\":\"foo:6.42.0\",\n" + " \"wantedVespaVersion\":\"6.42.0\",\n" + " \"rebootGeneration\": 1,\n" + " \"currentRebootGeneration\": 0,\n" + " \"failCount\": 0,\n" + " \"wantToRetire\" : false,\n" + " \"history\":[{\"type\":\"readied\",\"at\":123,\"type\":\"system\"},{\"type\":\"reserved\",\"at\":123,\"agent\":\"application\"},{\"type\":\"activated\",\"at\":123,\"agent\":\"application\"}],\n" + " \"ipAddresses\":[\"::1\", \"127.0.0.1\"]\n" + "}";
node = nodeSerializer.fromJson(State.active, Utf8.toBytes(json));
assertEquals(Collections.emptySet(), node.additionalIpAddresses());
}
use of com.yahoo.vespa.hosted.provision.Node in project vespa by vespa-engine.
the class NodeAllocation method acceptNode.
private Node acceptNode(PrioritizableNode prioritizableNode, boolean wantToRetire) {
Node node = prioritizableNode.node;
if (!wantToRetire) {
if (!node.state().equals(Node.State.active)) {
// reactivated node - make sure its not retired
node = node.unretire();
prioritizableNode.node = node;
}
acceptedOfRequestedFlavor++;
} else {
++wasRetiredJustNow;
// Retire nodes which are of an unwanted flavor, retired flavor or have an overlapping parent host
node = node.retire(nodeRepository.clock().instant());
prioritizableNode.node = node;
}
if (!node.allocation().get().membership().cluster().equals(cluster)) {
// group may be different
node = setCluster(cluster, node);
prioritizableNode.node = node;
}
indexes.add(node.allocation().get().membership().index());
highestIndex.set(Math.max(highestIndex.get(), node.allocation().get().membership().index()));
nodes.add(prioritizableNode);
return node;
}
use of com.yahoo.vespa.hosted.provision.Node in project vespa by vespa-engine.
the class NodeAllocation method finalNodes.
/**
* Make the number of <i>non-retired</i> nodes in the list equal to the requested number
* of nodes, and retire the rest of the list. Only retire currently active nodes.
* Prefer to retire nodes of the wrong flavor.
* Make as few changes to the retired set as possible.
*
* @param surplusNodes this will add nodes not any longer needed by this group to this list
* @return the final list of nodes
*/
List<Node> finalNodes(List<Node> surplusNodes) {
int currentRetiredCount = (int) nodes.stream().filter(node -> node.node.allocation().get().membership().retired()).count();
int deltaRetiredCount = requestedNodes.idealRetiredCount(nodes.size(), currentRetiredCount) - currentRetiredCount;
if (deltaRetiredCount > 0) {
// retire until deltaRetiredCount is 0, prefer to retire higher indexes to minimize redistribution
for (PrioritizableNode node : byDecreasingIndex(nodes)) {
if (!node.node.allocation().get().membership().retired() && node.node.state().equals(Node.State.active)) {
node.node = node.node.retire(Agent.application, nodeRepository.clock().instant());
// offer this node to other groups
surplusNodes.add(node.node);
if (--deltaRetiredCount == 0)
break;
}
}
} else if (deltaRetiredCount < 0) {
// unretire until deltaRetiredCount is 0
for (PrioritizableNode node : byIncreasingIndex(nodes)) {
if (node.node.allocation().get().membership().retired() && hasCompatibleFlavor(node.node)) {
node.node = node.node.unretire();
if (++deltaRetiredCount == 0)
break;
}
}
}
for (PrioritizableNode node : nodes) {
node.node = requestedNodes.assignRequestedFlavor(node.node);
// Set whether the node is exclusive
Allocation allocation = node.node.allocation().get();
node.node = node.node.with(allocation.with(allocation.membership().with(allocation.membership().cluster().exclusive(requestedNodes.isExclusive()))));
}
return nodes.stream().map(n -> n.node).collect(Collectors.toList());
}
Aggregations