use of org.openkilda.wfm.share.flow.resources.ResourceAllocationException in project open-kilda by telstra.
the class YFlowCreateServiceTest method shouldFailIfNoResourcesAvailable.
@Test
public void shouldFailIfNoResourcesAvailable() throws RecoverableException, UnroutableFlowException, ResourceAllocationException, DuplicateKeyException {
// given
YFlowRequest request = buildYFlowRequest("test_failed_yflow", "test_flow_1", "test_flow_2").build();
preparePathComputation("test_flow_1", buildFirstSubFlowPathPair());
preparePathComputation("test_flow_2", buildSecondSubFlowPathPair());
prepareYPointComputation(SWITCH_SHARED, SWITCH_FIRST_EP, SWITCH_SECOND_EP, SWITCH_TRANSIT);
doThrow(new ResourceAllocationException(injectedErrorMessage)).when(flowResourcesManager).allocateMeter(eq(request.getYFlowId()), eq(SWITCH_TRANSIT));
// when
processRequestAndSpeakerCommands(request);
// then
verifyNoSpeakerInteraction(yFlowCreateHubCarrier);
verify(flowResourcesManager, times(METER_ALLOCATION_RETRIES_LIMIT + 1)).allocateMeter(eq(request.getYFlowId()), eq(SWITCH_TRANSIT));
verifyYFlowIsAbsent(request.getYFlowId());
}
use of org.openkilda.wfm.share.flow.resources.ResourceAllocationException in project open-kilda by telstra.
the class BaseResourceAllocationAction method allocateFlowResources.
@SneakyThrows
protected FlowResources allocateFlowResources(Flow flow, PathId forwardPathId, PathId reversePathId) throws ResourceAllocationException {
RetryPolicy<FlowResources> resourceAllocationRetryPolicy = transactionManager.<FlowResources>getDefaultRetryPolicy().handle(ResourceAllocationException.class).handle(ConstraintViolationException.class).onRetry(e -> log.warn("Failure in resource allocation. Retrying #{}...", e.getAttemptCount(), e.getLastFailure())).onRetriesExceeded(e -> log.warn("Failure in resource allocation. No more retries", e.getFailure())).withMaxRetries(resourceAllocationRetriesLimit);
FlowResources flowResources = transactionManager.doInTransaction(resourceAllocationRetryPolicy, () -> resourcesManager.allocateFlowResources(flow, forwardPathId, reversePathId));
log.debug("Resources have been allocated: {}", flowResources);
return flowResources;
}
use of org.openkilda.wfm.share.flow.resources.ResourceAllocationException in project open-kilda by telstra.
the class BaseResourceAllocationAction method allocatePathPair.
@SneakyThrows
protected GetPathsResult allocatePathPair(Flow flow, PathId newForwardPathId, PathId newReversePathId, boolean forceToIgnoreBandwidth, List<PathId> pathsToReuseBandwidth, FlowPathPair oldPaths, boolean allowOldPaths, String sharedBandwidthGroupId, Predicate<GetPathsResult> whetherCreatePathSegments) throws RecoverableException, UnroutableFlowException, ResourceAllocationException {
// Lazy initialisable map with reused bandwidth...
Supplier<Map<IslEndpoints, Long>> reuseBandwidthPerIsl = Suppliers.memoize(() -> {
Map<IslEndpoints, Long> result = new HashMap<>();
if (pathsToReuseBandwidth != null && !pathsToReuseBandwidth.isEmpty()) {
pathsToReuseBandwidth.stream().map(pathId -> flow.getPath(pathId).orElse(flowPathRepository.findById(pathId).orElse(null))).filter(Objects::nonNull).flatMap(path -> path.getSegments().stream()).forEach(segment -> {
IslEndpoints isl = new IslEndpoints(segment.getSrcSwitchId().toString(), segment.getSrcPort(), segment.getDestSwitchId().toString(), segment.getDestPort());
result.put(isl, result.getOrDefault(isl, 0L) + segment.getBandwidth());
});
}
return result;
});
RetryPolicy<GetPathsResult> pathAllocationRetryPolicy = new RetryPolicy<GetPathsResult>().handle(RecoverableException.class).handle(ResourceAllocationException.class).handle(UnroutableFlowException.class).handle(PersistenceException.class).onRetry(e -> log.warn("Failure in path allocation. Retrying #{}...", e.getAttemptCount(), e.getLastFailure())).onRetriesExceeded(e -> log.warn("Failure in path allocation. No more retries", e.getFailure())).withMaxRetries(pathAllocationRetriesLimit);
if (pathAllocationRetryDelay > 0) {
pathAllocationRetryPolicy.withDelay(Duration.ofMillis(pathAllocationRetryDelay));
}
try {
return Failsafe.with(pathAllocationRetryPolicy).get(() -> {
GetPathsResult potentialPath;
if (forceToIgnoreBandwidth) {
boolean originalIgnoreBandwidth = flow.isIgnoreBandwidth();
flow.setIgnoreBandwidth(true);
potentialPath = pathComputer.getPath(flow);
flow.setIgnoreBandwidth(originalIgnoreBandwidth);
} else {
potentialPath = pathComputer.getPath(flow, pathsToReuseBandwidth);
}
boolean newPathFound = isNotSamePath(potentialPath, oldPaths);
if (allowOldPaths || newPathFound) {
if (!newPathFound) {
log.debug("Found the same path for flow {}. Proceed with recreating it", flow.getFlowId());
}
if (whetherCreatePathSegments.test(potentialPath)) {
boolean ignoreBandwidth = forceToIgnoreBandwidth || flow.isIgnoreBandwidth();
List<PathSegment> forwardSegments = flowPathBuilder.buildPathSegments(newForwardPathId, potentialPath.getForward(), flow.getBandwidth(), ignoreBandwidth, sharedBandwidthGroupId);
List<PathSegment> reverseSegments = flowPathBuilder.buildPathSegments(newReversePathId, potentialPath.getReverse(), flow.getBandwidth(), ignoreBandwidth, sharedBandwidthGroupId);
transactionManager.doInTransaction(() -> {
createPathSegments(forwardSegments, reuseBandwidthPerIsl);
createPathSegments(reverseSegments, reuseBandwidthPerIsl);
});
}
return potentialPath;
}
return null;
});
} catch (FailsafeException ex) {
throw ex.getCause();
}
}
use of org.openkilda.wfm.share.flow.resources.ResourceAllocationException in project open-kilda by telstra.
the class AllocateYFlowResourcesAction method perform.
@Override
public void perform(S from, S to, E event, C context, T stateMachine) {
try {
String yFlowId = stateMachine.getYFlowId();
YFlowResources newResources;
// This could be a retry.
if (stateMachine.getNewResources() != null) {
newResources = stateMachine.getNewResources();
} else {
newResources = new YFlowResources();
stateMachine.setNewResources(newResources);
}
YFlow yFlow = getYFlow(yFlowId);
SwitchId sharedEndpoint = yFlow.getSharedEndpoint().getSwitchId();
if (newResources.getSharedEndpointResources() == null) {
EndpointResources sharedEndpointResources = allocateMeterAsEndpointResources(yFlowId, sharedEndpoint, yFlow.getMaximumBandwidth());
newResources.setSharedEndpointResources(sharedEndpointResources);
stateMachine.saveActionToHistory("A new meter was allocated for the y-flow shared endpoint", format("A new meter %s / %s was allocated", sharedEndpointResources.getMeterId(), sharedEndpointResources.getEndpoint()));
}
if (newResources.getMainPathYPointResources() == null) {
List<FlowPath> subFlowsReversePaths = new ArrayList<>();
yFlow.getSubFlows().forEach(subFlow -> {
Flow flow = subFlow.getFlow();
FlowPath path = flow.getReversePath();
if (path == null) {
throw new FlowProcessingException(ErrorType.INTERNAL_ERROR, format("Missing a reverse path for %s sub-flow", flow.getFlowId()));
} else {
subFlowsReversePaths.add(path);
}
});
EndpointResources yPointResources = allocateYPointResources(yFlowId, sharedEndpoint, yFlow.getMaximumBandwidth(), subFlowsReversePaths.toArray(new FlowPath[0]));
newResources.setMainPathYPointResources(yPointResources);
stateMachine.saveActionToHistory("A new meter was allocated for the y-flow y-point", format("A new meter %s / %s was allocated", yPointResources.getMeterId(), yPointResources.getEndpoint()));
}
if (yFlow.isAllocateProtectedPath() && newResources.getProtectedPathYPointResources() == null) {
List<FlowPath> subFlowsReversePaths = new ArrayList<>();
yFlow.getSubFlows().forEach(subFlow -> {
Flow flow = subFlow.getFlow();
FlowPath path = flow.getProtectedReversePath();
if (path == null) {
if (flow.getStatus() == FlowStatus.UP) {
throw new FlowProcessingException(ErrorType.INTERNAL_ERROR, format("Missing a protected path for %s sub-flow", flow.getFlowId()));
} else {
log.warn("Sub-flow {} has no expected protected path and status {}", flow.getFlowId(), flow.getStatus());
}
} else {
subFlowsReversePaths.add(path);
}
});
if (subFlowsReversePaths.size() > 1) {
EndpointResources yPointResources = allocateYPointResources(yFlowId, sharedEndpoint, yFlow.getMaximumBandwidth(), subFlowsReversePaths.toArray(new FlowPath[0]));
newResources.setProtectedPathYPointResources(yPointResources);
stateMachine.saveActionToHistory("A new meter was allocated for the y-flow protected path y-point", format("A new meter %s / %s was allocated", yPointResources.getMeterId(), yPointResources.getEndpoint()));
} else {
stateMachine.saveActionToHistory("Skip meter allocation for the y-flow protected path y-point", "Y-flow protected path y-point can't be found - sub-flow(s) lacks a protected path");
}
}
transactionManager.doInTransaction(() -> {
YFlow yFlowToUpdate = getYFlow(yFlowId);
yFlowToUpdate.setYPoint(newResources.getMainPathYPointResources().getEndpoint());
yFlowToUpdate.setMeterId(newResources.getMainPathYPointResources().getMeterId());
if (newResources.getProtectedPathYPointResources() != null) {
yFlowToUpdate.setProtectedPathYPoint(newResources.getProtectedPathYPointResources().getEndpoint());
yFlowToUpdate.setProtectedPathMeterId(newResources.getProtectedPathYPointResources().getMeterId());
} else {
yFlowToUpdate.setProtectedPathYPoint(null);
yFlowToUpdate.setProtectedPathMeterId(null);
}
yFlowToUpdate.setSharedEndpointMeterId(newResources.getSharedEndpointResources().getMeterId());
});
notifyStats(stateMachine, newResources);
} catch (ResourceAllocationException ex) {
String errorMessage = format("Failed to allocate y-flow resources. %s", ex.getMessage());
stateMachine.saveErrorToHistory(errorMessage, ex);
stateMachine.fireError(errorMessage);
}
}
use of org.openkilda.wfm.share.flow.resources.ResourceAllocationException in project open-kilda by telstra.
the class AllocatePrimaryResourcesAction method allocate.
@Override
protected void allocate(FlowUpdateFsm stateMachine) throws RecoverableException, UnroutableFlowException, ResourceAllocationException {
String flowId = stateMachine.getFlowId();
Set<String> flowIds = Sets.newHashSet(flowId);
if (stateMachine.getBulkUpdateFlowIds() != null) {
flowIds.addAll(stateMachine.getBulkUpdateFlowIds());
}
log.debug("Finding paths for flows {}", flowIds);
List<PathId> pathIdsToReuse = new ArrayList<>(flowPathRepository.findActualPathIdsByFlowIds(flowIds));
pathIdsToReuse.addAll(stateMachine.getRejectedPaths());
Flow tmpFlow = getFlow(flowId);
FlowPathPair oldPaths = new FlowPathPair(tmpFlow.getForwardPath(), tmpFlow.getReversePath());
PathId newForwardPathId = resourcesManager.generatePathId(flowId);
PathId newReversePathId = resourcesManager.generatePathId(flowId);
log.debug("Finding a new primary path for flow {}", flowId);
GetPathsResult allocatedPaths = allocatePathPair(tmpFlow, newForwardPathId, newReversePathId, false, pathIdsToReuse, oldPaths, true, stateMachine.getSharedBandwidthGroupId(), path -> true);
if (allocatedPaths == null) {
throw new ResourceAllocationException("Unable to allocate a path");
}
log.debug("New primary paths have been allocated: {}", allocatedPaths);
stateMachine.setBackUpPrimaryPathComputationWayUsed(allocatedPaths.isBackUpPathComputationWayUsed());
stateMachine.setNewPrimaryForwardPath(newForwardPathId);
stateMachine.setNewPrimaryReversePath(newReversePathId);
log.debug("Allocating resources for a new primary path of flow {}", flowId);
FlowResources flowResources = allocateFlowResources(tmpFlow, newForwardPathId, newReversePathId);
stateMachine.setNewPrimaryResources(flowResources);
FlowPathPair createdPaths = createFlowPathPair(flowId, flowResources, allocatedPaths, false, stateMachine.getSharedBandwidthGroupId());
log.debug("New primary path has been created: {}", createdPaths);
setMirrorPointsToNewPath(oldPaths.getForwardPathId(), newForwardPathId);
setMirrorPointsToNewPath(oldPaths.getReversePathId(), newReversePathId);
saveAllocationActionWithDumpsToHistory(stateMachine, tmpFlow, "primary", createdPaths);
}
Aggregations