use of com.yahoo.vespa.orchestrator.model.NodeGroup in project vespa by vespa-engine.
the class HostedVespaPolicy method grantSuspensionRequest.
// TODO: Remove later - currently used for backward compatibility testing
@Override
public void grantSuspensionRequest(ApplicationInstance applicationInstance, HostName hostName, MutableStatusRegistry hostStatusService) throws HostStateChangeDeniedException {
NodeGroup nodeGroup = new NodeGroup(applicationInstance);
nodeGroup.addNode(hostName);
ApplicationApi applicationApi = new ApplicationApiImpl(nodeGroup, hostStatusService, clusterControllerClientFactory);
grantSuspensionRequest(applicationApi);
}
use of com.yahoo.vespa.orchestrator.model.NodeGroup in project vespa by vespa-engine.
the class OrchestratorImpl method suspend.
@Override
public void suspend(HostName hostName) throws HostStateChangeDeniedException, HostNameNotFoundException {
ApplicationInstance appInstance = getApplicationInstance(hostName);
NodeGroup nodeGroup = new NodeGroup(appInstance, hostName);
suspendGroup(nodeGroup);
}
use of com.yahoo.vespa.orchestrator.model.NodeGroup in project vespa by vespa-engine.
the class OrchestratorImpl method acquirePermissionToRemove.
@Override
public void acquirePermissionToRemove(HostName hostName) throws OrchestrationException {
ApplicationInstance appInstance = getApplicationInstance(hostName);
NodeGroup nodeGroup = new NodeGroup(appInstance, hostName);
try (MutableStatusRegistry statusRegistry = statusService.lockApplicationInstance_forCurrentThreadOnly(appInstance.reference())) {
ApplicationApi applicationApi = new ApplicationApiImpl(nodeGroup, statusRegistry, clusterControllerClientFactory);
policy.acquirePermissionToRemove(applicationApi);
}
}
use of com.yahoo.vespa.orchestrator.model.NodeGroup in project vespa by vespa-engine.
the class OrchestratorImpl method nodeGroupsOrderedForSuspend.
/**
* PROBLEM
* Take the example of 2 Docker hosts:
* - Docker host 1 has two nodes A1 and B1, belonging to the application with
* a globally unique ID A and B, respectively.
* - Similarly, Docker host 2 has two nodes running content nodes A2 and B2,
* and we assume both A1 and A2 (and B1 and B2) have services within the same service cluster.
*
* Suppose both Docker hosts wanting to reboot, and
* - Docker host 1 asks to suspend A1 and B1, while
* - Docker host 2 asks to suspend B2 and A2.
*
* The Orchestrator may allow suspend of A1 and B2, before requesting the suspension of B1 and A2.
* None of these can be suspended (assuming max 1 suspended content node per content cluster),
* and so both requests for suspension will fail.
*
* Note that it's not a deadlock - both client will fail immediately and resume both A1 and B2 before
* responding to the client, and if host 1 asks later w/o host 2 asking at the same time,
* it will be given permission to suspend. However if both hosts were to request in lock-step,
* there would be starvation. And in general, it would fail requests for suspension more
* than necessary.
*
* SOLUTION
* The solution we're using is to order the hostnames by the globally unique application instance ID,
* e.g. hosted-vespa:routing:dev:some-region:default. In the example above, it would guarantee
* Docker host 2 would ensure ask to suspend B2 before A2. We take care of that ordering here.
*
* NodeGroups complicate the above picture a little: Each A1, A2, B1, and B2 is a NodeGroup that may
* contain several nodes (on the same Docker host). But the argument still applies.
*/
private List<NodeGroup> nodeGroupsOrderedForSuspend(List<HostName> hostNames) throws HostNameNotFoundException {
Map<ApplicationInstanceReference, NodeGroup> nodeGroupMap = new HashMap<>(hostNames.size());
for (HostName hostName : hostNames) {
ApplicationInstance application = getApplicationInstance(hostName);
NodeGroup nodeGroup = nodeGroupMap.get(application.reference());
if (nodeGroup == null) {
nodeGroup = new NodeGroup(application);
nodeGroupMap.put(application.reference(), nodeGroup);
}
nodeGroup.addNode(hostName);
}
return nodeGroupMap.values().stream().sorted(OrchestratorImpl::compareNodeGroupsForSuspend).collect(Collectors.toList());
}
use of com.yahoo.vespa.orchestrator.model.NodeGroup in project vespa by vespa-engine.
the class HostedVespaClusterPolicyTest method verifyGroupGoingDownIsFine.
private void verifyGroupGoingDownIsFine(boolean noServicesOutsideGroupIsDown, boolean noServicesInGroupIsUp, int percentageOfServicesDownIfGroupIsAllowedToBeDown, boolean expectSuccess) {
when(clusterApi.noServicesOutsideGroupIsDown()).thenReturn(noServicesOutsideGroupIsDown);
when(clusterApi.noServicesInGroupIsUp()).thenReturn(noServicesInGroupIsUp);
when(clusterApi.percentageOfServicesDownIfGroupIsAllowedToBeDown()).thenReturn(20);
doReturn(ConcurrentSuspensionLimitForCluster.TEN_PERCENT).when(policy).getConcurrentSuspensionLimit(clusterApi);
when(clusterApi.serviceType()).thenReturn(new ServiceType("service-type"));
when(clusterApi.percentageOfServicesDown()).thenReturn(5);
when(clusterApi.percentageOfServicesDownIfGroupIsAllowedToBeDown()).thenReturn(percentageOfServicesDownIfGroupIsAllowedToBeDown);
when(clusterApi.servicesDownAndNotInGroupDescription()).thenReturn("services-down-and-not-in-group");
when(clusterApi.nodesAllowedToBeDownNotInGroupDescription()).thenReturn("allowed-to-be-down");
NodeGroup nodeGroup = mock(NodeGroup.class);
when(clusterApi.getNodeGroup()).thenReturn(nodeGroup);
when(nodeGroup.toCommaSeparatedString()).thenReturn("node-group");
when(clusterApi.noServicesInGroupIsUp()).thenReturn(false);
try {
policy.verifyGroupGoingDownIsFine(clusterApi);
if (!expectSuccess) {
fail();
}
} catch (HostStateChangeDeniedException e) {
if (!expectSuccess) {
assertEquals("Changing the state of node-group would violate enough-services-up: " + "Suspension percentage for service type service-type would increase from " + "5% to 13%, over the limit of 10%. These instances may be down: " + "services-down-and-not-in-group and these hosts are allowed to be down: " + "allowed-to-be-down", e.getMessage());
assertEquals("enough-services-up", e.getConstraintName());
}
}
}
Aggregations