From 3695abf3a498d78b7141299401619c2b801255f6 Mon Sep 17 00:00:00 2001 From: Sergii Iakovenko Date: Thu, 28 Apr 2022 19:58:56 +0300 Subject: [PATCH 1/8] Unmark DRAFT from y-flow API --- .../openkilda/northbound/controller/v2/YFlowControllerV2.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/YFlowControllerV2.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/YFlowControllerV2.java index 0c986aeb898..4f8e94934aa 100644 --- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/YFlowControllerV2.java +++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/controller/v2/YFlowControllerV2.java @@ -15,8 +15,6 @@ package org.openkilda.northbound.controller.v2; -import static org.openkilda.northbound.config.SwaggerConfig.DRAFT_API_TAG; - import org.openkilda.northbound.controller.BaseController; import org.openkilda.northbound.dto.v2.yflows.SubFlowsDump; import org.openkilda.northbound.dto.v2.yflows.YFlow; @@ -50,7 +48,7 @@ import java.util.concurrent.CompletableFuture; import javax.validation.Valid; -@Api(tags = {DRAFT_API_TAG}) +@Api @RestController @RequestMapping("/v2/y-flows") public class YFlowControllerV2 extends BaseController { From a7291e08b4695a70b2333bb29b5cb1d9ba1c3327 Mon Sep 17 00:00:00 2001 From: Sergii Iakovenko Date: Tue, 31 May 2022 11:00:21 +0300 Subject: [PATCH 2/8] Fix validation and sync for one-switch y-flow. --- .../actions/OnSubFlowAllocatedAction.java | 11 +++++++---- .../actions/StartReroutingYFlowAction.java | 9 ++++++--- .../reroute/actions/ValidateYFlowAction.java | 8 ++++++-- .../validation/YFlowValidationService.java | 6 ++++++ .../flows/yflows/YFlowValidationSpec.groovy | 18 ++++++++---------- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowAllocatedAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowAllocatedAction.java index d5afb0ba303..c4be5daa15d 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowAllocatedAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowAllocatedAction.java @@ -16,6 +16,7 @@ package org.openkilda.wfm.topology.flowhs.fsm.yflow.reroute.actions; import static java.lang.String.format; +import static java.util.Collections.emptyList; import org.openkilda.messaging.Message; import org.openkilda.messaging.command.yflow.SubFlowPathDto; @@ -25,7 +26,6 @@ import org.openkilda.messaging.info.event.PathInfoData; import org.openkilda.model.Flow; import org.openkilda.model.FlowPath; -import org.openkilda.model.PathSegment; import org.openkilda.model.SwitchId; import org.openkilda.model.YFlow; import org.openkilda.model.YSubFlow; @@ -91,7 +91,7 @@ private Message buildRerouteResponseMessage(YFlowRerouteFsm stateMachine) { .orElseThrow(() -> new FlowProcessingException(ErrorType.NOT_FOUND, format("Y-flow %s not found", yFlowId))); SwitchId sharedSwitchId = yflow.getSharedEndpoint().getSwitchId(); - List paths = new ArrayList<>(); + List paths = new ArrayList<>(); for (YSubFlow subFlow : yflow.getSubFlows()) { Flow flow = subFlow.getFlow(); FlowPath flowPath = flow.getPaths().stream() @@ -106,8 +106,11 @@ private Message buildRerouteResponseMessage(YFlowRerouteFsm stateMachine) { return paths; }); - List sharedPathSegments = IntersectionComputer.calculatePathIntersectionFromSource(flowPaths); - PathInfoData sharedPath = FlowPathMapper.INSTANCE.map(sharedPathSegments); + List nonEmptyPaths = flowPaths.stream() + .filter(fp -> !fp.getSegments().isEmpty()).collect(Collectors.toList()); + PathInfoData sharedPath = FlowPathMapper.INSTANCE.map(nonEmptyPaths.size() >= 2 + ? IntersectionComputer.calculatePathIntersectionFromSource(nonEmptyPaths) : emptyList()); + List subFlowPathDtos = flowPaths.stream() .map(flowPath -> new SubFlowPathDto(flowPath.getFlowId(), FlowPathMapper.INSTANCE.map(flowPath))) .sorted(Comparator.comparing(SubFlowPathDto::getFlowId)) diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/StartReroutingYFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/StartReroutingYFlowAction.java index d21ad6bd4a2..706ae99f139 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/StartReroutingYFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/StartReroutingYFlowAction.java @@ -15,10 +15,11 @@ package org.openkilda.wfm.topology.flowhs.fsm.yflow.reroute.actions; +import static java.util.Collections.emptyList; + import org.openkilda.messaging.command.yflow.SubFlowPathDto; import org.openkilda.messaging.info.event.PathInfoData; import org.openkilda.model.FlowPath; -import org.openkilda.model.PathSegment; import org.openkilda.model.SwitchId; import org.openkilda.model.YFlow; import org.openkilda.model.YSubFlow; @@ -68,8 +69,10 @@ protected void perform(State from, State to, Event event, YFlowRerouteContext co stateMachine.setOldYFlowPathCookies(flowPaths.stream() .map(FlowPath::getCookie).map(FlowSegmentCookie::getValue).collect(Collectors.toList())); - List sharedPathSegments = IntersectionComputer.calculatePathIntersectionFromSource(flowPaths); - PathInfoData sharedPath = FlowPathMapper.INSTANCE.map(sharedPathSegments); + List nonEmptyPaths = flowPaths.stream() + .filter(fp -> !fp.getSegments().isEmpty()).collect(Collectors.toList()); + PathInfoData sharedPath = FlowPathMapper.INSTANCE.map(nonEmptyPaths.size() >= 2 + ? IntersectionComputer.calculatePathIntersectionFromSource(nonEmptyPaths) : emptyList()); stateMachine.setOldSharedPath(sharedPath); List subFlowPathDtos = flowPaths.stream() diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java index 3ab9bd4df11..c5db880466b 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java @@ -112,8 +112,12 @@ protected Optional performWithResponse(State from, State to, Event even Flow mainAffinitySubFlow = subFlows.stream() .filter(flow -> flow.getFlowId().equals(flow.getAffinityGroupId())) .findFirst() - .orElseThrow(() -> new FlowProcessingException(ErrorType.DATA_INVALID, - format("Main affinity sub-flow of the y-flow %s not found", yFlowId))); + .orElseGet(() -> + subFlows.stream() + .findFirst() + .orElseThrow(() -> new FlowProcessingException(ErrorType.DATA_INVALID, + format("Main affinity sub-flow of the y-flow %s not found", yFlowId)))); + stateMachine.setMainAffinityFlowId(mainAffinitySubFlow.getFlowId()); boolean mainAffinitySubFlowIsAffected = isFlowAffected(mainAffinitySubFlow, affectedIsls); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/validation/YFlowValidationService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/validation/YFlowValidationService.java index 83388e55f54..a8b77e4977a 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/validation/YFlowValidationService.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/validation/YFlowValidationService.java @@ -179,6 +179,12 @@ private List buildYFlowSimpleSwitchRules(Flow subFlow, SwitchI break; } } + } else { + List reverseIngressRules = + simpleSwitchRuleConverter.buildIngressSimpleSwitchRules(subFlow, reverse, null, + flowMeterMinBurstSizeInKbits, flowMeterBurstCoefficient); + result.addAll(simpleSwitchRuleConverter.buildYFlowIngressSimpleSwitchRules(reverseIngressRules, + yPoint, yPointMeterId)); } return result; } diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowValidationSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowValidationSpec.groovy index 0390cafab70..3b2e8b93e5b 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowValidationSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowValidationSpec.groovy @@ -82,11 +82,10 @@ class YFlowValidationSpec extends HealthCheckSpecification { description: "multiSwtich y-flow", yFlow: { SwitchTriplet swTriplet -> yFlowHelper.randomYFlow(swTriplet) } ], - //https://github.com/telstra/open-kilda/issues/4825 -// [ -// description: "one-switch y-flow", -// yFlow: { SwitchTriplet swTriplet -> yFlowHelper.singleSwitchYFlow(swTriplet.shared) } -// ] + [ + description: "one-switch y-flow", + yFlow: { SwitchTriplet swTriplet -> yFlowHelper.singleSwitchYFlow(swTriplet.shared) } + ] ] } @@ -149,11 +148,10 @@ class YFlowValidationSpec extends HealthCheckSpecification { description: "multiSwtich y-flow", yFlow: { SwitchTriplet swTriplet -> yFlowHelper.randomYFlow(swTriplet) } ], - //https://github.com/telstra/open-kilda/issues/4824 -// [ -// description: "one-switch y-flow", -// yFlow: { SwitchTriplet swTriplet -> yFlowHelper.singleSwitchYFlow(swTriplet.ep2) } -// ] + [ + description: "one-switch y-flow", + yFlow: { SwitchTriplet swTriplet -> yFlowHelper.singleSwitchYFlow(swTriplet.ep2) } + ] ] } From fb1dd5cd1660a6640142dbb18d21951d8a7c4dda Mon Sep 17 00:00:00 2001 From: Dmitriy Bogun Date: Thu, 17 Mar 2022 09:33:25 +0200 Subject: [PATCH 3/8] True flow sync Replace synthetic flow sync operation (implemented as reroute that allowed to reuse current flow paths) with true "sync" operation. True sync operation do not touch existing flow resources and paths, it only produces path segment install requests for existing paths and track their execution. --- .../crud/path/flow-path-delete-fsm.png | Bin 0 -> 205960 bytes .../crud/path/flow-path-delete-fsm.puml | 38 ++ .../crud/path/flow-patth-install-fsm.png | Bin 0 -> 209173 bytes .../crud/path/flow-patth-install-fsm.puml | 41 ++ .../hub-and-spoke/crud/sync/flow-sync-fsm.png | Bin 0 -> 216933 bytes .../crud/sync/flow-sync-fsm.puml | 46 ++ .../openkilda/messaging/error/ErrorType.java | 2 + .../share/history/model/FlowEventData.java | 1 + .../logger/FlowOperationsDashboardLogger.java | 41 ++ .../SpeakerFlowSegmentRequestBuilder.java | 56 ++- .../wfm/share/utils/CarrierContext.java | 67 +++ .../flowhs/service/FlowCommandBuilder.java | 16 + .../FlowSegmentRequestFactoriesSequence.java | 31 ++ .../api/response/SpeakerResponse.java | 2 + .../command/flow/FlowSyncRequest.java | 32 ++ .../command/flow/FlowRerouteRequest.java | 14 +- .../wfm/topology/flowhs/FlowHsTopology.java | 38 +- .../topology/flowhs/FlowHsTopologyConfig.java | 12 + .../flowhs/bolts/FlowSyncHubBolt.java | 277 ++++++++++++ .../wfm/topology/flowhs/bolts/RouterBolt.java | 13 + .../wfm/topology/flowhs/fsm/FsmUtil.java | 54 +++ .../FlowProcessingWithHistorySupportFsm.java | 16 +- .../path/DummyFlowPathHistoryFormatter.java | 60 +++ .../FlowPathAbortInstallHistoryFormatter.java | 67 +++ .../FlowPathAbortRemoveHistoryFormatter.java | 67 +++ .../flowhs/fsm/path/FlowPathContext.java | 27 ++ .../flowhs/fsm/path/FlowPathFsmBase.java | 285 ++++++++++++ .../fsm/path/FlowPathHistoryFormatter.java | 46 ++ .../flowhs/fsm/path/FlowPathInstallFsm.java | 175 ++++++++ .../path/FlowPathInstallHistoryFormatter.java | 70 +++ .../flowhs/fsm/path/FlowPathOperation.java | 37 ++ .../flowhs/fsm/path/FlowPathRemoveFsm.java | 163 +++++++ .../path/FlowPathRemoveHistoryFormatter.java | 70 +++ .../path/FlowPathVerifyHistoryFormatter.java | 70 +++ .../flowhs/fsm/path/PendingEntry.java | 59 +++ .../flowhs/fsm/sync/FlowSyncContext.java | 33 ++ .../topology/flowhs/fsm/sync/FlowSyncFsm.java | 294 ++++++++++++ .../actions/CreateSyncHandlersAction.java | 138 ++++++ .../sync/actions/FailedCompleteAction.java | 105 +++++ .../fsm/sync/actions/FlowSyncSetupAction.java | 94 ++++ .../actions/PathOperationResponseAction.java | 75 ++++ .../sync/actions/SuccessCompleteAction.java | 79 ++++ .../flowhs/model/path/FlowPathChunk.java | 32 ++ .../model/path/FlowPathOperationConfig.java | 23 + .../path/FlowPathOperationDescriptor.java | 32 ++ .../flowhs/model/path/FlowPathReference.java | 30 ++ .../flowhs/model/path/FlowPathRequest.java | 55 +++ .../flowhs/model/path/FlowPathResult.java | 24 + .../flowhs/model/path/FlowPathResultCode.java | 20 + .../service/FlowSwapEndpointsHubService.java | 2 +- .../flowhs/service/FlowSyncCarrier.java | 33 ++ .../flowhs/service/FlowSyncService.java | 104 +++++ .../service/common/FlowHistoryCarrier.java | 33 ++ .../flowhs/service/common/FlowHsService.java | 41 ++ .../common/FlowProcessingFsmRegister.java | 2 +- .../service/common/FlowProcessingService.java | 2 +- .../common/FsmBasedProcessingService.java | 22 +- .../flowhs/service/common/FsmRegister.java | 12 +- .../flowhs/service/path/FlowPathCarrier.java | 23 + .../flowhs/service/path/FlowPathService.java | 130 ++++++ .../flowhs/service/FlowSyncServiceTest.java | 236 ++++++++++ .../service/path/FlowPathServiceTest.java | 417 ++++++++++++++++++ .../utils/FlowSegmentRequestMetaFactory.java | 94 ++++ .../utils/SequentialNumberGenerator.java | 51 +++ .../service/impl/FlowServiceImpl.java | 38 +- .../reroute/service/RerouteServiceTest.java | 1 - .../spec/flows/FlowSyncSpec.groovy | 2 + .../flows/FlowValidationNegativeSpec.groovy | 2 +- 68 files changed, 4193 insertions(+), 79 deletions(-) create mode 100644 docs/design/hub-and-spoke/crud/path/flow-path-delete-fsm.png create mode 100644 docs/design/hub-and-spoke/crud/path/flow-path-delete-fsm.puml create mode 100644 docs/design/hub-and-spoke/crud/path/flow-patth-install-fsm.png create mode 100644 docs/design/hub-and-spoke/crud/path/flow-patth-install-fsm.puml create mode 100644 docs/design/hub-and-spoke/crud/sync/flow-sync-fsm.png create mode 100644 docs/design/hub-and-spoke/crud/sync/flow-sync-fsm.puml create mode 100644 src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/utils/CarrierContext.java create mode 100644 src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSegmentRequestFactoriesSequence.java create mode 100644 src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/messaging/command/flow/FlowSyncRequest.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/FlowSyncHubBolt.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/FsmUtil.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/DummyFlowPathHistoryFormatter.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortInstallHistoryFormatter.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortRemoveHistoryFormatter.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathContext.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathFsmBase.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathHistoryFormatter.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallFsm.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallHistoryFormatter.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathOperation.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveFsm.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveHistoryFormatter.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathVerifyHistoryFormatter.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/PendingEntry.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncContext.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncFsm.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/CreateSyncHandlersAction.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FailedCompleteAction.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FlowSyncSetupAction.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/PathOperationResponseAction.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/SuccessCompleteAction.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathChunk.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationConfig.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationDescriptor.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathReference.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathRequest.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResult.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResultCode.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncCarrier.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncService.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHistoryCarrier.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHsService.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathCarrier.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathService.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncServiceTest.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathServiceTest.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/FlowSegmentRequestMetaFactory.java create mode 100644 src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/SequentialNumberGenerator.java diff --git a/docs/design/hub-and-spoke/crud/path/flow-path-delete-fsm.png b/docs/design/hub-and-spoke/crud/path/flow-path-delete-fsm.png new file mode 100644 index 0000000000000000000000000000000000000000..06f4ff34d1d0f4098b0e34b62506c03f60d5b395 GIT binary patch literal 205960 zcmeFZby$?^*EWpXt!x9>1}Lpk0s_*~sKC%j=YU8_2m(XLps0v+OG`IMH=`n5(j7{7 zcfD)C{d~{FpkI=nsXV#l*=S{))Wo;r0? z_s*N@ySr!D&6Dqc`wI_wxlC9VMRGwFtv+iNEPCx;IPoKJ@-79dPfFyY!asuC4&C`?T@#U=K{jyq%WA6^_^)y^xluM)qfYZ;;^O7re*Q$2g_`U^BumIvL4xVBgquKqw8dCWNPGOox>_l zgW4ruaDKBWx3m;mUWn_B_wMPUOp0aKwlH1V#YL%XpR2uTx80JhzfF@JD3M%AxMZZX zD=}SAf?;HYcCArqOMQw)vZcA!jt*%>5tbP zR|v0HQ?fk${7Sp@&aFR)o;Y54`0$~yJpB!N$A`kgxBvb_A~6g{;i}`MPh#$O&fobH zkH#P8%3o$ja$6ymAN$R?B4zSswyk5T`&~xu_Pz@kxwd+T;zJ0W{`477o&V?mI0uSX z$g$CJ@-rqUg81kEI6K$cul(09M{;fX7(w-)-Tm>)Q-C6dGj2Hw#bA0M}fY7wf> z)vMDdh~l$r9r}5JXQ+}VieGj3rJ%u5V+i9E{bFmZP>x?IYBsQRpZCyNR$To4w)(-= zpoPh2X@jNx>D|p<9RpQrI=Xo#t2+{2QA+RRu{U1BJ$Zn&*7D`5jM7iYa$A!FqgWSO z9jVZJ4&!D=57Sk$7@Wqc34}Q8>>uIVS>V&P352oeRQ+^r)RLC=w)}RDPWCbde~DpB zM6#~UTo0eOs sW9d`UvhRXl|xMg0-u{_ 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 z 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 a<`I5nUMFYzOpOCu59~kmQ^t?SFa8^1UZ>*# literal 0 HcmV?d00001 diff --git a/docs/design/hub-and-spoke/crud/path/flow-path-delete-fsm.puml b/docs/design/hub-and-spoke/crud/path/flow-path-delete-fsm.puml new file mode 100644 index 00000000000..3d248211898 --- /dev/null +++ b/docs/design/hub-and-spoke/crud/path/flow-path-delete-fsm.puml @@ -0,0 +1,38 @@ +@startuml +title Flow path delete FSM state diagram + +[*] --> DELETE + +DELETE: enter / activate next segments chunk +DELETE: enter / fire "no_more_chunks" if there is no more chunks +DELETE: enter / emit DELETE request for each segment in active chunk +DELETE: enter / fire "chunk_complete" if there is no more pending requests +DELETE: enter / fire "next" +DELETE --> WAIT_PENDING: next +DELETE --> REVERT: error / set result_code into SPEAKER_ERROR +DELETE --> REVERT_WAIT_PENDING: cancel / set result_code into CANCEL +DELETE --> END: (chunk_complete | no_more_chunks) + +WAIT_PENDING --> REVERT: error / set result_code into SPEAKER_ERROR +WAIT_PENDING --> REVERT_WAIT_PENDING: cancel / set result_code into CANCEL +WAIT_PENDING --> DELETE: chunk_complete +WAIT_PENDING: speaker_response / handle speaker response +WAIT_PENDING: speaker_response / [no more pending request && no error responses received] fire "chunk_complete" +WAIT_PENDING: speaker_response / [no more pending request && error responses are present] fire "error" + +REVERT_WAIT_PENDING --> REVERT: (error | chunk_complete) +REVERT_WAIT_PENDING: speaker_response / handle speaker response +REVERT_WAIT_PENDING: speaker_response / [no more pending request && no error responses received] fire "chunk_complete" +REVERT_WAIT_PENDING: speaker_response / [no more pending request && error responses are present] fire "error" + +REVERT: enter / [! is revert enabled] fire "chunk_complete" +REVERT: enter / assemble and activate revert chunk +REVERT: enter / emit INSTALL request for each segment in active chunk +REVERT --> END: (chunk_complete | error) +REVERT: speaker_response / handle speaker response +REVERT: speaker_response / [no more pending request && no error responses received] fire "chunk_complete" +REVERT: speaker_response / [no more pending request && error responses are present] fire "error" + +END: enter / [result code is null] set result_code into success +END --> [*] +@enduml diff --git a/docs/design/hub-and-spoke/crud/path/flow-patth-install-fsm.png b/docs/design/hub-and-spoke/crud/path/flow-patth-install-fsm.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a59e98c8bf0eece47df5e73721741a971cc2e4 GIT binary patch literal 209173 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 zɬ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%0ApKE;ea{5kqt6^%t&ZFeu6f{#J@^~Ol4J@_ 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 AW&i*H literal 0 HcmV?d00001 diff --git a/docs/design/hub-and-spoke/crud/path/flow-patth-install-fsm.puml b/docs/design/hub-and-spoke/crud/path/flow-patth-install-fsm.puml new file mode 100644 index 00000000000..5890bb1af11 --- /dev/null +++ b/docs/design/hub-and-spoke/crud/path/flow-patth-install-fsm.puml @@ -0,0 +1,41 @@ +@startuml +title Flow path install FSM state diagram + +[*] --> INSTALL + +INSTALL: enter / activate next segments chunk +INSTALL: enter / fire "no_more_chunks" if there is no more chunks +INSTALL: enter / emit INSTALL request for each segment in active chunk +INSTALL: enter / fire "chunk_complete" if there is no more pending requests +INSTALL --> REVERT: error / set result_code into SPEAKER_ERROR +INSTALL --> REVERT_WAIT_PENDING: cancel / set result_code into CANCEL +INSTALL --> VERIFY: chunk_complete +INSTALL --> END: no_more_chunks +INSTALL: speaker_response / handle speaker response +INSTALL: speaker_response / [no more pending request && no error responses received] fire "chunk_complete" +INSTALL: speaker_response / [no more pending request && error responses are present] fire "error" + +VERIFY: enter / emit VERIFY request for each segment in active chunk +VERIFY --> REVERT: error / set result_code into SPEAKER_ERROR +VERIFY --> REVERT_WAIT_PENDING: cancel / set result_code into CANCEL +VERIFY --> INSTALL: chunk_complete +VERIFY: speaker_response / handle speaker response +VERIFY: speaker_response / [no more pending request && no error responses received] fire "chunk_complete" +VERIFY: speaker_response / [no more pending request && error responses are present] fire "error" + +REVERT_WAIT_PENDING --> END: (chunk_complete | error) +REVERT_WAIT_PENDING: speaker_response / handle speaker response +REVERT_WAIT_PENDING: speaker_response / [no more pending request && no error responses received] fire "chunk_complete" +REVERT_WAIT_PENDING: speaker_response / [no more pending request && error responses are present] fire "error" + +REVERT: enter / [! is revert enabled] fire "chunk_complete" +REVERT: enter / assemble and activate revert chunk +REVERT: enter / emit DELETE request for each segment in active chunk +REVERT --> END: (chunk_complete | error) +REVERT: speaker_response / handle speaker response +REVERT: speaker_response / [no more pending request && no error responses received] fire "chunk_complete" +REVERT: speaker_response / [no more pending request && error responses are present] fire "error" + +END: enter / [result code is null] set result_code into success +END --> [*] +@enduml diff --git a/docs/design/hub-and-spoke/crud/sync/flow-sync-fsm.png b/docs/design/hub-and-spoke/crud/sync/flow-sync-fsm.png new file mode 100644 index 0000000000000000000000000000000000000000..8349b1ac35df5ec9174614a27e49dc48b19824ff GIT binary patch literal 216933 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Ǒ)&_Ta_;+kH5D8cex3eEye(C!7Ums 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 SETUP +SETUP: enter / fire "error" if flow is IN_PROGRESS status +SETUP: enter / set flow status to IN_PROGRESS +SETUP: enter / apply postponed flow changes +SETUP --> SYNC: next +SETUP --> COMMIT_ERROR: error + +SYNC: enter / launch main path install operation +SYNC: enter / [have protected path] launch protected path install operation +SYNC --> SYNC_FAIL: sync_fail +SYNC --> COMMIT_SUCCESS: guard_passed +SYNC --> CANCEL: error +SYNC --> CANCEL: timeout / report global timeout +SYNC: path_operation_response / handle path operation response +SYNC: path_operation_response / fire "sync_fail" on failed path response +SYNC: path_operation_response / fire "guard_passed" if no more pending operations + +CANCEL: enter / request cancel path operation for all pending operations +CANCEL --> COMMIT_ERROR: guard_passed +CANCEL: path_operation_response / handle path operation response +CANCEL: path_operation_response / fire "guard_passed" if no more pending operations +CANCEL: error / fire "guard_passed" if no pending operations +CANCEL: timeout / report global timeout + +SYNC_FAIL: enter / fire "guard_passed" if no pending operations +SYNC_FAIL --> COMMIT_ERROR: guard_passed +SYNC_FAIL --> CANCEL: error +SYNC_FAIL --> CANCEL: timeout / report global timeout +SYNC_FAIL: path_operation_response / handle path operation response +SYNC_FAIL: path_operation_response / fire "guard_passed" if no more pending operations + +COMMIT_SUCCESS: enter / update flow status +COMMIT_SUCCESS: enter / send success response +COMMIT_SUCCESS --> FINISHED: next +COMMIT_SUCCESS --> COMMIT_ERROR: error + +COMMIT_ERROR: enter / update flow status +COMMIT_ERROR: enter / send failed response +COMMIT_ERROR --> FINISHED_WITH_ERROR: next + +FINISHED --> [*] +FINISHED_WITH_ERROR --> [*] +@enduml diff --git a/src-java/base-topology/base-messaging/src/main/java/org/openkilda/messaging/error/ErrorType.java b/src-java/base-topology/base-messaging/src/main/java/org/openkilda/messaging/error/ErrorType.java index a27a23442c3..e70b3050a2a 100644 --- a/src-java/base-topology/base-messaging/src/main/java/org/openkilda/messaging/error/ErrorType.java +++ b/src-java/base-topology/base-messaging/src/main/java/org/openkilda/messaging/error/ErrorType.java @@ -66,6 +66,8 @@ public enum ErrorType { */ ALREADY_EXISTS("Object already exists"), + BUSY("Operation can't be processed at this moment"), + /** * The error message for invalid request data. */ diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/FlowEventData.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/FlowEventData.java index ca754c90389..580d0cd2998 100644 --- a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/FlowEventData.java +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/FlowEventData.java @@ -45,6 +45,7 @@ public enum Event { UPDATE("Flow updating"), REROUTE("Flow rerouting"), DELETE("Flow deleting"), + SYNC("Flow paths sync"), PATH_SWAP("Flow paths swap"), SWAP_ENDPOINTS("Flows swap endpoints"), FLOW_LOOP_CREATE("Flow loop creating"), diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/logger/FlowOperationsDashboardLogger.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/logger/FlowOperationsDashboardLogger.java index 2d80f66942e..ac1a1c59e3c 100644 --- a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/logger/FlowOperationsDashboardLogger.java +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/logger/FlowOperationsDashboardLogger.java @@ -41,6 +41,8 @@ public class FlowOperationsDashboardLogger extends AbstractDashboardLogger { private static final String UPDATE_RESULT_EVENT = "flow_update_result"; private static final String FLOW_DELETE_EVENT = "flow_delete"; private static final String DELETE_RESULT_EVENT = "flow_delete_result"; + private static final String FLOW_SYNC_EVENT = "flow_sync"; + private static final String SYNC_RESULT_EVENT = "flow_sync_result"; private static final String PATHS_SWAP_EVENT = "paths_swap"; private static final String REROUTE_EVENT = "flow_reroute"; private static final String REROUTE_RESULT_EVENT = "flow_reroute_result"; @@ -305,6 +307,45 @@ public void onFailedFlowDelete(String flowId, String failureReason) { data); } + /** + * Log a flow-sync event. + */ + public void onFlowSync(String flowId) { + Map data = new HashMap<>(); + data.put(TAG, "flow-sync"); + data.put(FLOW_ID, flowId); + data.put(EVENT_TYPE, FLOW_SYNC_EVENT); + invokeLogger(Level.INFO, String.format("Performing flow \"%s\" SYNC", flowId), data); + } + + /** + * Log a flow-sync-successful event. + */ + public void onSuccessfulFlowSync(String flowId) { + Map data = new HashMap<>(); + data.put(TAG, "flow-sync-success"); + data.put(FLOW_ID, flowId); + data.put(EVENT_TYPE, FLOW_SYNC_EVENT); + data.put("sync-result", "successful"); + invokeLogger(Level.INFO, String.format("Flow \"%s\" SYNC success", flowId), data); + } + + /** + * Log a flow-sync-failed event. + */ + public void onFailedFlowSync(String flowId, int failedPathsCount, int totalPathsCount) { + Map data = new HashMap<>(); + data.put(TAG, "flow-sync-failed"); + data.put(FLOW_ID, flowId); + data.put(EVENT_TYPE, FLOW_SYNC_EVENT); + data.put("sync-result", "failed"); + invokeLogger( + Level.INFO, String.format( + "Flow \"%s\" SYNC failed - %d of %d path have failed to sync", + flowId, failedPathsCount, totalPathsCount), + data); + } + /** * Log a flow-endpoint-swap event. */ diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/service/SpeakerFlowSegmentRequestBuilder.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/service/SpeakerFlowSegmentRequestBuilder.java index ad28b80342e..10e9bc195e6 100644 --- a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/service/SpeakerFlowSegmentRequestBuilder.java +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/service/SpeakerFlowSegmentRequestBuilder.java @@ -53,12 +53,14 @@ import org.openkilda.wfm.share.model.SpeakerRequestBuildContext; import org.openkilda.wfm.share.model.SpeakerRequestBuildContext.PathContext; import org.openkilda.wfm.topology.flowhs.service.FlowCommandBuilder; +import org.openkilda.wfm.topology.flowhs.service.FlowSegmentRequestFactoriesSequence; import com.fasterxml.uuid.Generators; import com.fasterxml.uuid.NoArgGenerator; import lombok.NonNull; import lombok.Value; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.List; @@ -92,7 +94,8 @@ public List buildAll(CommandContext context, Flow flo public List buildAll(CommandContext context, Flow flow, FlowPath path, SpeakerRequestBuildContext speakerRequestBuildContext, MirrorContext mirrorContext) { - return makeRequests(context, flow, path, null, true, true, true, speakerRequestBuildContext, mirrorContext); + return mergePair(makeRequests( + context, flow, path, null, true, true, true, speakerRequestBuildContext, mirrorContext)); } @Override @@ -107,8 +110,8 @@ public List buildAll(CommandContext context, Flow flo FlowPath reversePath, SpeakerRequestBuildContext speakerRequestBuildContext, MirrorContext mirrorContext) { - return makeRequests(context, flow, forwardPath, reversePath, true, true, true, speakerRequestBuildContext, - mirrorContext); + return mergePair(makeRequests( + context, flow, forwardPath, reversePath, true, true, true, speakerRequestBuildContext, mirrorContext)); } @Override @@ -136,8 +139,15 @@ public List buildAllExceptIngress( @Override public List buildAllExceptIngress( CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, MirrorContext mirrorContext) { + return mergePair(makeRequests(context, flow, path, oppositePath, false, true, true, + SpeakerRequestBuildContext.getEmpty(), mirrorContext)); + } + + @Override + public Pair + buildAllExceptIngressSeverally(CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath) { return makeRequests(context, flow, path, oppositePath, false, true, true, - SpeakerRequestBuildContext.getEmpty(), mirrorContext); + SpeakerRequestBuildContext.getEmpty(), MirrorContext.DEFAULT); } @Override @@ -158,8 +168,16 @@ public List buildIngressOnly( public List buildIngressOnly( CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, SpeakerRequestBuildContext speakerRequestBuildContext, MirrorContext mirrorContext) { + return mergePair(makeRequests(context, flow, path, oppositePath, true, false, false, + speakerRequestBuildContext, mirrorContext)); + } + + @Override + public Pair buildIngressOnlySeverally( + CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, + SpeakerRequestBuildContext speakerRequestBuildContext) { return makeRequests(context, flow, path, oppositePath, true, false, false, - speakerRequestBuildContext, mirrorContext); + speakerRequestBuildContext, MirrorContext.DEFAULT); } @Override @@ -187,9 +205,9 @@ public List buildEgressOnly( @Override public List buildEgressOnly( CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, MirrorContext mirrorContext) { - return makeRequests( + return mergePair(makeRequests( context, flow, path, oppositePath, false, false, true, SpeakerRequestBuildContext.getEmpty(), - mirrorContext); + mirrorContext)); } @Override @@ -226,12 +244,15 @@ private List makeRequests( doIngress, doTransit, doEgress, createRulesContext(pathContext), mirrorContext)); } - private List makeRequests( + private Pair makeRequests( CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, boolean doIngress, boolean doTransit, boolean doEgress, SpeakerRequestBuildContext speakerRequestBuildContext, MirrorContext mirrorContext) { + boolean isSwapped = false; + // TODO: this swap is weird, need to clean this up and not to rely on luck. if (path == null) { + isSwapped = true; path = oppositePath; oppositePath = null; speakerRequestBuildContext = SpeakerRequestBuildContext.builder() @@ -258,9 +279,11 @@ private List makeRequests( } } - List requests = new ArrayList<>(makePathRequests(flow, path, context, encapsulation, + FlowSegmentRequestFactoriesSequence left = new FlowSegmentRequestFactoriesSequence( + makePathRequests(flow, path, context, encapsulation, doIngress, doTransit, doEgress, createRulesContext(speakerRequestBuildContext.getForward()), mirrorContext)); + FlowSegmentRequestFactoriesSequence right = new FlowSegmentRequestFactoriesSequence(); if (oppositePath != null) { if (!flow.isOneSwitchFlow()) { try { @@ -273,10 +296,14 @@ private List makeRequests( encapsulation = DELETE_ENCAPSULATION_STUB; } } - requests.addAll(makePathRequests(flow, oppositePath, context, encapsulation, doIngress, doTransit, doEgress, + right.addAll(makePathRequests(flow, oppositePath, context, encapsulation, doIngress, doTransit, doEgress, createRulesContext(speakerRequestBuildContext.getReverse()), mirrorContext)); } - return requests; + + if (isSwapped) { + return Pair.of(right, left); + } + return Pair.of(left, right); } private RulesContext createRulesContext(PathContext pathContext) { @@ -650,4 +677,11 @@ private Optional makeMirrorConfig(@NonNull FlowPath flowPath, @Non return Optional.empty(); } + + private static List mergePair( + Pair source) { + List results = new ArrayList<>(source.getLeft()); + results.addAll(source.getRight()); + return results; + } } diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/utils/CarrierContext.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/utils/CarrierContext.java new file mode 100644 index 00000000000..1349b0bc178 --- /dev/null +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/utils/CarrierContext.java @@ -0,0 +1,67 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.share.utils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.function.FailableConsumer; + +import java.util.ArrayDeque; +import java.util.Deque; + +@Slf4j +public class CarrierContext { + private final Deque queue = new ArrayDeque<>(); + + /** + * Access context value. + */ + public T getContext() { + T value = queue.peek(); + if (value == null) { + throw new IllegalStateException("Attempt to access carrier context without defining it's value in advance"); + } + return value; + } + + /** + * Add new entry into queue. + */ + public void apply(T payload, FailableConsumer handler) { + try { + applyUnsafe(payload, handler); + } catch (Exception e) { + throwUnexpectedException(e); + } + } + + /** + * Add new entry into queue, can throw exceptions. + */ + public void applyUnsafe(T payload, FailableConsumer handler) throws Exception { + queue.push(payload); + log.trace("Set carrier context to: {}", payload); + try { + handler.accept(payload); + } finally { + queue.pop(); + log.trace("Reset carrier context to: {}", queue.peek()); + } + } + + public void throwUnexpectedException(Exception cause) { + throw new IllegalStateException("Got unexpected exception", cause); + } +} diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowCommandBuilder.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowCommandBuilder.java index 3ee3c34fe61..d28a6c08b31 100644 --- a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowCommandBuilder.java +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowCommandBuilder.java @@ -23,6 +23,8 @@ import org.openkilda.wfm.share.model.SpeakerRequestBuildContext; import org.openkilda.wfm.share.model.SpeakerRequestBuildContext.PathContext; +import org.apache.commons.lang3.tuple.Pair; + import java.util.List; public interface FlowCommandBuilder { @@ -84,6 +86,13 @@ List buildAllExceptIngress( List buildAllExceptIngress( CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, MirrorContext mirrorContext); + /** + * Build commands for transit(if needed) and egress rules for provided paths severally (i.e. each path + * segments returned severally). + */ + Pair buildAllExceptIngressSeverally( + CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath); + /** * Build install commands for ingress rules for active forward and reverse paths. */ @@ -104,6 +113,13 @@ List buildIngressOnly( CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, SpeakerRequestBuildContext speakerRequestBuildContext, MirrorContext mirrorContext); + /** + * Build commands for ingress segments for provided paths and return them severally. + */ + Pair buildIngressOnlySeverally( + CommandContext context, Flow flow, FlowPath path, FlowPath oppositePath, + SpeakerRequestBuildContext speakerRequestBuildContext); + /** * Build install commands for ingress rules for provided paths. */ diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSegmentRequestFactoriesSequence.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSegmentRequestFactoriesSequence.java new file mode 100644 index 00000000000..91b114b4df9 --- /dev/null +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSegmentRequestFactoriesSequence.java @@ -0,0 +1,31 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service; + +import org.openkilda.floodlight.api.request.factory.FlowSegmentRequestFactory; + +import java.util.ArrayList; +import java.util.Collection; + +public class FlowSegmentRequestFactoriesSequence extends ArrayList { + public FlowSegmentRequestFactoriesSequence() { + super(); + } + + public FlowSegmentRequestFactoriesSequence(Collection source) { + super(source); + } +} diff --git a/src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/floodlight/api/response/SpeakerResponse.java b/src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/floodlight/api/response/SpeakerResponse.java index af3271c4f1e..f65dee913ef 100644 --- a/src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/floodlight/api/response/SpeakerResponse.java +++ b/src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/floodlight/api/response/SpeakerResponse.java @@ -22,10 +22,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.NonNull; +import lombok.ToString; import java.util.UUID; @Getter +@ToString(callSuper = true) public abstract class SpeakerResponse extends AbstractMessage { @JsonProperty("command_id") protected final UUID commandId; diff --git a/src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/messaging/command/flow/FlowSyncRequest.java b/src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/messaging/command/flow/FlowSyncRequest.java new file mode 100644 index 00000000000..173a7c1eb90 --- /dev/null +++ b/src-java/floodlight-service/floodlight-api/src/main/java/org/openkilda/messaging/command/flow/FlowSyncRequest.java @@ -0,0 +1,32 @@ +/* Copyright 2020 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.messaging.command.flow; + +import org.openkilda.messaging.command.CommandData; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; + +@Data +@EqualsAndHashCode(callSuper = false) +@JsonNaming(value = SnakeCaseStrategy.class) +public class FlowSyncRequest extends CommandData { + @NonNull + String flowId; +} diff --git a/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java b/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java index ac1b034a366..58fa6860ed8 100644 --- a/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java +++ b/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java @@ -43,12 +43,6 @@ public class FlowRerouteRequest extends CommandData { @JsonProperty("path_ids") protected Set affectedIsl; - /** - * Update flow even if path will not be changed. - */ - @JsonProperty("force") - private boolean force; - @JsonProperty("effectively_down") private boolean effectivelyDown; @@ -78,11 +72,17 @@ public FlowRerouteRequest(@NonNull @JsonProperty("flowid") String flowId, @JsonProperty("reason") String reason, @JsonProperty("manual") boolean manual) { this.flowId = flowId; - this.force = force; this.effectivelyDown = effectivelyDown; this.affectedIsl = affectedIsl; this.reason = reason; this.ignoreBandwidth = ignoreBandwidth; this.manual = manual; + + // field "force" have been removed as part of "true flow sync" feature. Constructor argument left for now, to + // not ruin JSON compatibility for transition period. + } + + public boolean isForce() { + return false; // dummy getter for removed "force" field. } } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopology.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopology.java index afb332e839d..dd775a82a42 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopology.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopology.java @@ -65,6 +65,7 @@ import org.openkilda.wfm.topology.flowhs.bolts.FlowRerouteHubBolt; import org.openkilda.wfm.topology.flowhs.bolts.FlowRerouteHubBolt.FlowRerouteConfig; import org.openkilda.wfm.topology.flowhs.bolts.FlowSwapEndpointsHubBolt; +import org.openkilda.wfm.topology.flowhs.bolts.FlowSyncHubBolt; import org.openkilda.wfm.topology.flowhs.bolts.FlowUpdateHubBolt; import org.openkilda.wfm.topology.flowhs.bolts.FlowUpdateHubBolt.FlowUpdateConfig; import org.openkilda.wfm.topology.flowhs.bolts.FlowValidationHubBolt; @@ -116,6 +117,7 @@ public StormTopology createTopology() { flowUpdateHub(tb, persistenceManager); flowRerouteHub(tb, persistenceManager); flowDeleteHub(tb, persistenceManager); + flowSyncHub(tb, persistenceManager); flowSwapProtectedHub(tb, persistenceManager); flowSwapEndpointsHub(tb, persistenceManager); flowCreateMirrorPointHub(tb, persistenceManager); @@ -165,7 +167,8 @@ private void zkBolt(TopologyBuilder topologyBuilder) { ZooKeeperBolt zooKeeperBolt = new ZooKeeperBolt(getConfig().getBlueGreenMode(), getZkTopoName(), getZookeeperConfig(), getBoltInstancesCount(ComponentId.FLOW_CREATE_HUB.name(), ComponentId.FLOW_UPDATE_HUB.name(), - ComponentId.FLOW_DELETE_HUB.name(), ComponentId.FLOW_PATH_SWAP_HUB.name(), + ComponentId.FLOW_DELETE_HUB.name(), FlowSyncHubBolt.BOLT_ID, + ComponentId.FLOW_PATH_SWAP_HUB.name(), ComponentId.FLOW_REROUTE_HUB.name(), ComponentId.FLOW_SWAP_ENDPOINTS_HUB.name(), ComponentId.FLOW_ROUTER_BOLT.name(), ComponentId.FLOW_CREATE_MIRROR_POINT_HUB.name(), ComponentId.FLOW_DELETE_MIRROR_POINT_HUB.name(), @@ -181,6 +184,7 @@ private void zkBolt(TopologyBuilder topologyBuilder) { .allGrouping(ComponentId.FLOW_CREATE_HUB.name(), ZkStreams.ZK.toString()) .allGrouping(ComponentId.FLOW_UPDATE_HUB.name(), ZkStreams.ZK.toString()) .allGrouping(ComponentId.FLOW_DELETE_HUB.name(), ZkStreams.ZK.toString()) + .allGrouping(FlowSyncHubBolt.BOLT_ID, ZkStreams.ZK.toString()) .allGrouping(ComponentId.FLOW_PATH_SWAP_HUB.name(), ZkStreams.ZK.toString()) .allGrouping(ComponentId.FLOW_REROUTE_HUB.name(), ZkStreams.ZK.toString()) .allGrouping(ComponentId.FLOW_SWAP_ENDPOINTS_HUB.name(), ZkStreams.ZK.toString()) @@ -336,6 +340,27 @@ private void flowDeleteHub(TopologyBuilder topologyBuilder, PersistenceManager p .directGrouping(CoordinatorBolt.ID); } + private void flowSyncHub(TopologyBuilder topologyBuilder, PersistenceManager persistenceManager) { + int hubTimeout = (int) TimeUnit.SECONDS.toMillis(topologyConfig.getSyncHubTimeoutSeconds()); + + FlowSyncHubBolt.FlowSyncConfig config = FlowSyncHubBolt.FlowSyncConfig.flowSyncBuilder() + .speakerCommandRetriesLimit(topologyConfig.getSyncSpeakerCommandRetries()) + .requestSenderComponent(ComponentId.FLOW_ROUTER_BOLT.name()) + .workerComponent(ComponentId.SPEAKER_WORKER.name()) + .lifeCycleEventComponent(ZooKeeperSpout.SPOUT_ID) + .timeoutMs(hubTimeout) + .autoAck(true) + .build(); + + FlowResourcesConfig flowResourcesConfig = configurationProvider.getConfiguration(FlowResourcesConfig.class); + FlowSyncHubBolt hubBolt = new FlowSyncHubBolt(config, persistenceManager, flowResourcesConfig); + declareBolt(topologyBuilder, hubBolt, FlowSyncHubBolt.BOLT_ID) + .fieldsGrouping(ComponentId.FLOW_ROUTER_BOLT.name(), Stream.ROUTER_TO_FLOW_SYNC_HUB.name(), FLOW_FIELD) + .directGrouping(ComponentId.SPEAKER_WORKER.name(), Stream.SPEAKER_WORKER_TO_HUB.name()) + .allGrouping(ZooKeeperSpout.SPOUT_ID) + .directGrouping(CoordinatorBolt.ID); + } + private void flowSwapEndpointsHub(TopologyBuilder topologyBuilder, PersistenceManager persistenceManager) { int hubTimeout = (int) TimeUnit.SECONDS.toMillis(topologyConfig.getSwapEndpointsHubTimeoutSeconds()); @@ -644,6 +669,7 @@ private void speakerWorkers(TopologyBuilder topologyBuilder) { .hubComponent(ComponentId.FLOW_PATH_SWAP_HUB.name()) .hubComponent(ComponentId.FLOW_REROUTE_HUB.name()) .hubComponent(ComponentId.FLOW_DELETE_HUB.name()) + .hubComponent(FlowSyncHubBolt.BOLT_ID) .hubComponent(ComponentId.FLOW_CREATE_MIRROR_POINT_HUB.name()) .hubComponent(ComponentId.FLOW_DELETE_MIRROR_POINT_HUB.name()) .hubComponent(ComponentId.YFLOW_CREATE_HUB.name()) @@ -660,6 +686,7 @@ private void speakerWorkers(TopologyBuilder topologyBuilder) { .fieldsGrouping(ComponentId.FLOW_PATH_SWAP_HUB.name(), Stream.HUB_TO_SPEAKER_WORKER.name(), FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_REROUTE_HUB.name(), Stream.HUB_TO_SPEAKER_WORKER.name(), FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_DELETE_HUB.name(), Stream.HUB_TO_SPEAKER_WORKER.name(), FIELDS_KEY) + .fieldsGrouping(FlowSyncHubBolt.BOLT_ID, Stream.HUB_TO_SPEAKER_WORKER.name(), FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_CREATE_MIRROR_POINT_HUB.name(), Stream.HUB_TO_SPEAKER_WORKER.name(), FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_DELETE_MIRROR_POINT_HUB.name(), Stream.HUB_TO_SPEAKER_WORKER.name(), @@ -732,6 +759,7 @@ private void coordinator(TopologyBuilder topologyBuilder) { .fieldsGrouping(ComponentId.FLOW_PATH_SWAP_HUB.name(), CoordinatorBolt.INCOME_STREAM, FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_REROUTE_HUB.name(), CoordinatorBolt.INCOME_STREAM, FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_DELETE_HUB.name(), CoordinatorBolt.INCOME_STREAM, FIELDS_KEY) + .fieldsGrouping(FlowSyncHubBolt.BOLT_ID, CoordinatorBolt.INCOME_STREAM, FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_SWAP_ENDPOINTS_HUB.name(), CoordinatorBolt.INCOME_STREAM, FIELDS_KEY) .fieldsGrouping(ComponentId.FLOW_VALIDATION_HUB.name(), CoordinatorBolt.INCOME_STREAM, FIELDS_KEY) .fieldsGrouping(ComponentId.YFLOW_CREATE_HUB.name(), CoordinatorBolt.INCOME_STREAM, FIELDS_KEY) @@ -751,6 +779,7 @@ private void northboundOutput(TopologyBuilder topologyBuilder) { .shuffleGrouping(ComponentId.FLOW_PATH_SWAP_HUB.name(), Stream.HUB_TO_NB_RESPONSE_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_REROUTE_HUB.name(), Stream.HUB_TO_NB_RESPONSE_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_DELETE_HUB.name(), Stream.HUB_TO_NB_RESPONSE_SENDER.name()) + .shuffleGrouping(ComponentId.FLOW_SYNC_HUB.name(), Stream.HUB_TO_NB_RESPONSE_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_SWAP_ENDPOINTS_HUB.name(), Stream.HUB_TO_NB_RESPONSE_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_CREATE_MIRROR_POINT_HUB.name(), Stream.HUB_TO_NB_RESPONSE_SENDER.name()) @@ -783,6 +812,7 @@ private void pingOutput(TopologyBuilder topologyBuilder) { .shuffleGrouping(ComponentId.FLOW_CREATE_HUB.name(), Stream.HUB_TO_PING_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_UPDATE_HUB.name(), Stream.HUB_TO_PING_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_DELETE_HUB.name(), Stream.HUB_TO_PING_SENDER.name()) + .shuffleGrouping(ComponentId.FLOW_SYNC_HUB.name(), Stream.HUB_TO_PING_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_REROUTE_HUB.name(), Stream.HUB_TO_PING_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_PATH_SWAP_HUB.name(), Stream.HUB_TO_PING_SENDER.name()) .shuffleGrouping(ComponentId.YFLOW_CREATE_HUB.name(), Stream.HUB_TO_PING_SENDER.name()) @@ -823,6 +853,7 @@ private void flowMonitoringTopologyOutput(TopologyBuilder topologyBuilder) { Stream.HUB_TO_FLOW_MONITORING_TOPOLOGY_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_DELETE_HUB.name(), Stream.HUB_TO_FLOW_MONITORING_TOPOLOGY_SENDER.name()) + .shuffleGrouping(ComponentId.FLOW_SYNC_HUB.name(), Stream.HUB_TO_FLOW_MONITORING_TOPOLOGY_SENDER.name()) .shuffleGrouping(ComponentId.YFLOW_CREATE_HUB.name(), Stream.HUB_TO_FLOW_MONITORING_TOPOLOGY_SENDER.name()) .shuffleGrouping(ComponentId.YFLOW_UPDATE_HUB.name(), @@ -844,6 +875,7 @@ private void statsTopologyOutput(TopologyBuilder topologyBuilder) { Stream.HUB_TO_STATS_TOPOLOGY_SENDER.name()) .shuffleGrouping(ComponentId.FLOW_DELETE_HUB.name(), Stream.HUB_TO_STATS_TOPOLOGY_SENDER.name()) + .shuffleGrouping(ComponentId.FLOW_SYNC_HUB.name(), Stream.HUB_TO_STATS_TOPOLOGY_SENDER.name()) .shuffleGrouping(ComponentId.YFLOW_CREATE_HUB.name(), Stream.HUB_TO_STATS_TOPOLOGY_SENDER.name()) .shuffleGrouping(ComponentId.YFLOW_UPDATE_HUB.name(), @@ -867,6 +899,8 @@ private void history(TopologyBuilder topologyBuilder) { grouping) .fieldsGrouping(ComponentId.FLOW_DELETE_HUB.name(), Stream.HUB_TO_HISTORY_TOPOLOGY_SENDER.name(), grouping) + .fieldsGrouping(ComponentId.FLOW_SYNC_HUB.name(), Stream.HUB_TO_HISTORY_TOPOLOGY_SENDER.name(), + grouping) .fieldsGrouping(ComponentId.FLOW_PATH_SWAP_HUB.name(), Stream.HUB_TO_HISTORY_TOPOLOGY_SENDER.name(), grouping) .fieldsGrouping(ComponentId.FLOW_SWAP_ENDPOINTS_HUB.name(), @@ -923,6 +957,7 @@ public enum ComponentId { FLOW_PATH_SWAP_HUB("flow.pathswap.hub.bolt"), FLOW_REROUTE_HUB("flow.reroute.hub.bolt"), FLOW_DELETE_HUB("flow.delete.hub.bolt"), + FLOW_SYNC_HUB("flow.sync.hub.bolt"), FLOW_SWAP_ENDPOINTS_HUB("flow.swap.endpoints.hub.bolt"), FLOW_CREATE_MIRROR_POINT_HUB("flow.create.mirror.point.hub.bolt"), FLOW_DELETE_MIRROR_POINT_HUB("flow.create.mirror.point.hub.bolt"), @@ -975,6 +1010,7 @@ public enum Stream { ROUTER_TO_FLOW_PATH_SWAP_HUB, ROUTER_TO_FLOW_REROUTE_HUB, ROUTER_TO_FLOW_DELETE_HUB, + ROUTER_TO_FLOW_SYNC_HUB, ROUTER_TO_FLOW_SWAP_ENDPOINTS_HUB, ROUTER_TO_FLOW_CREATE_MIRROR_POINT_HUB, ROUTER_TO_FLOW_DELETE_MIRROR_POINT_HUB, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopologyConfig.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopologyConfig.java index 0f440a7b44a..dcc7219b2f0 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopologyConfig.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/FlowHsTopologyConfig.java @@ -115,6 +115,18 @@ default String getFlowStatsNotifyTopic() { @Default("3") int getRerouteSpeakerCommandRetries(); + @Key("flow.sync.hub.timeout.seconds") + @Default("30") + int getSyncHubTimeoutSeconds(); + + @Key("flow.sync.speaker.timeout.seconds") + @Default("10") + int getSyncSpeakerTimeoutSeconds(); + + @Key("flow.sync.speaker.command.retries") + @Default("3") + int getSyncSpeakerCommandRetries(); + @Key("flow.delete.hub.timeout.seconds") @Default("30") int getDeleteHubTimeoutSeconds(); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/FlowSyncHubBolt.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/FlowSyncHubBolt.java new file mode 100644 index 00000000000..d7c6d50fde6 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/FlowSyncHubBolt.java @@ -0,0 +1,277 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.bolts; + +import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.HUB_TO_FLOW_MONITORING_TOPOLOGY_SENDER; +import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.HUB_TO_HISTORY_TOPOLOGY_SENDER; +import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.HUB_TO_NB_RESPONSE_SENDER; +import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.HUB_TO_PING_SENDER; +import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.HUB_TO_SPEAKER_WORKER; +import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.HUB_TO_STATS_TOPOLOGY_SENDER; +import static org.openkilda.wfm.topology.utils.KafkaRecordTranslator.FIELD_ID_PAYLOAD; + +import org.openkilda.bluegreen.LifecycleEvent; +import org.openkilda.floodlight.api.request.SpeakerRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.messaging.Message; +import org.openkilda.messaging.command.CommandData; +import org.openkilda.messaging.command.CommandMessage; +import org.openkilda.messaging.command.flow.FlowSyncRequest; +import org.openkilda.messaging.command.flow.PeriodicPingCommand; +import org.openkilda.messaging.info.InfoMessage; +import org.openkilda.model.PathId; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.error.PipelineException; +import org.openkilda.wfm.share.flow.resources.FlowResourcesConfig; +import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowHistoryHolder; +import org.openkilda.wfm.share.hubandspoke.HubBolt; +import org.openkilda.wfm.share.utils.CarrierContext; +import org.openkilda.wfm.share.utils.KeyProvider; +import org.openkilda.wfm.share.zk.ZkStreams; +import org.openkilda.wfm.share.zk.ZooKeeperBolt; +import org.openkilda.wfm.topology.flowhs.FlowHsTopology.ComponentId; +import org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream; +import org.openkilda.wfm.topology.flowhs.exception.DuplicateKeyException; +import org.openkilda.wfm.topology.flowhs.exception.UnknownKeyException; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResult; +import org.openkilda.wfm.topology.flowhs.service.FlowSyncCarrier; +import org.openkilda.wfm.topology.flowhs.service.FlowSyncService; +import org.openkilda.wfm.topology.flowhs.service.path.FlowPathCarrier; +import org.openkilda.wfm.topology.flowhs.service.path.FlowPathService; +import org.openkilda.wfm.topology.utils.MessageKafkaTranslator; + +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import org.apache.storm.topology.OutputFieldsDeclarer; +import org.apache.storm.tuple.Fields; +import org.apache.storm.tuple.Tuple; +import org.apache.storm.tuple.Values; + +public class FlowSyncHubBolt extends HubBolt implements FlowSyncCarrier, FlowPathCarrier { + public static final String BOLT_ID = ComponentId.FLOW_SYNC_HUB.name(); + + private final FlowSyncConfig config; + private final FlowResourcesConfig flowResourcesConfig; + + private transient FlowSyncService syncService; + private transient FlowPathService pathService; + + private transient CarrierContext carrierContext; + private LifecycleEvent deferredShutdownEvent; + + public FlowSyncHubBolt( + @NonNull FlowSyncConfig config, @NonNull PersistenceManager persistenceManager, + @NonNull FlowResourcesConfig flowResourcesConfig) { + super(persistenceManager, config); + this.config = config; + this.flowResourcesConfig = flowResourcesConfig; + } + + @Override + protected void onRequest(Tuple input) throws PipelineException { + FlowSyncRequest request = pullValue(input, FIELD_ID_PAYLOAD, FlowSyncRequest.class); + carrierContext.apply(pullKey(input), key -> handleRequest(key, request)); + } + + @Override + protected void onWorkerResponse(Tuple input) throws PipelineException { + SpeakerFlowSegmentResponse response = pullValue(input, FIELD_ID_PAYLOAD, SpeakerFlowSegmentResponse.class); + carrierContext.apply(pullKey(input), key -> handleWorkerResponse(key, response)); + } + + @Override + protected void onTimeout(String coordinatorKey, Tuple tuple) throws PipelineException { + carrierContext.apply(coordinatorKey, key -> syncService.handleTimeout(key)); + } + + @Override + protected boolean deactivate(LifecycleEvent event) { + // pathService do not process any external requests (only requests from syncService) so it can to not implement + // enable/disable feature and do not need to be called here. + if (syncService.deactivate()) { + return true; + } + deferredShutdownEvent = event; + return false; + } + + @Override + protected void activate() { + syncService.activate(); + } + + private void handleRequest(String serviceKey, FlowSyncRequest request) { + syncService.handleRequest(serviceKey, request, getCommandContext()); + } + + private void handleWorkerResponse(String workerKey, SpeakerFlowSegmentResponse response) { + carrierContext.apply(KeyProvider.getParentKey(workerKey), serviceKey -> { + try { + // FlowSyncService do not communicate with speaker, so only FlowPathService can consume speaker + // responses. + pathService.handleSpeakerResponse(serviceKey, response); + } catch (UnknownKeyException e) { + log.warn("Received a speaker response with unknown key {}.", serviceKey); + } + }); + } + + private String newPathServiceKey(PathId pathId) { + return KeyProvider.joinKeys(pathId.toString(), carrierContext.getContext()); + } + + // -- carrier -- + + @Override + public void sendSpeakerRequest(SpeakerRequest request) { + String requestKey = KeyProvider.joinKeys(request.getCommandId().toString(), carrierContext.getContext()); + emit(HUB_TO_SPEAKER_WORKER.name(), getCurrentTuple(), makeOfSpeakerTuple(requestKey, request)); + } + + @Override + public void sendPeriodicPingNotification(String flowId, boolean enabled) { + // TODO(surabujin): ensure usage + PeriodicPingCommand payload = new PeriodicPingCommand(flowId, enabled); + emit(Stream.HUB_TO_PING_SENDER.name(), getCurrentTuple(), makePingTuple(payload)); + } + + @Override + public void sendHistoryUpdate(FlowHistoryHolder payload) { + emit(Stream.HUB_TO_HISTORY_TOPOLOGY_SENDER.name(), getCurrentTuple(), makeHistoryTuple(payload)); + } + + @Override + public void cancelTimeoutCallback(String key) { + cancelCallback(key); + } + + @Override + public void sendInactive() { + getOutput().emit(ZkStreams.ZK.toString(), new Values(deferredShutdownEvent, getCommandContext())); + deferredShutdownEvent = null; + } + + @Override + public void sendNorthboundResponse(Message message) { + emit(Stream.HUB_TO_NB_RESPONSE_SENDER.name(), getCurrentTuple(), makeNorthboundTuple(message)); + } + + private Values makeNorthboundTuple(Message message) { + return new Values(carrierContext.getContext(), message, getCommandContext()); + } + + private Values makeOfSpeakerTuple(String requestKey, SpeakerRequest request) { + return new Values(requestKey, request, getCommandContext()); + } + + private Values makePingTuple(CommandData payload) { + CommandContext commandContext = getCommandContext(); + Message message = new CommandMessage( + payload, commandContext.getCreateTime(), commandContext.getCorrelationId()); + return new Values(carrierContext.getContext(), message, commandContext); + } + + private Values makeHistoryTuple(FlowHistoryHolder payload) { + CommandContext commandContext = getCommandContext(); + InfoMessage message = new InfoMessage(payload, commandContext.getCreateTime(), + commandContext.getCorrelationId()); + return new Values(payload.getTaskId(), message, getCommandContext()); + } + + @Override + public void launchFlowPathInstallation( + @NonNull FlowPathRequest request, @NonNull FlowPathOperationConfig config, + @NonNull CommandContext commandContext) throws DuplicateKeyException { + try { + carrierContext.applyUnsafe(newPathServiceKey( + request.getReference().getPathId()), + pathServiceKey -> pathService.installPath(request, pathServiceKey, config, commandContext)); + } catch (DuplicateKeyException e) { + throw e; + } catch (Exception e) { + carrierContext.throwUnexpectedException(e); + } + } + + @Override + public void cancelFlowPathOperation(PathId pathId) throws UnknownKeyException { + try { + carrierContext.applyUnsafe( + newPathServiceKey(pathId), + pathServiceKey -> pathService.cancelOperation(pathServiceKey)); + } catch (UnknownKeyException e) { + throw e; + } catch (Exception e) { + carrierContext.throwUnexpectedException(e); + } + } + + @Override + public void processFlowPathOperationResults(FlowPathResult result) { + syncService.handlePathSyncResponse(result.getReference(), result.getResultCode()); + } + + // -- storm API -- + + @Override + protected void init() { + super.init(); + + final FlowResourcesManager resourcesManager = new FlowResourcesManager(persistenceManager, flowResourcesConfig); + final FlowPathOperationConfig pathOperationConfig = new FlowPathOperationConfig( + config.getSpeakerCommandRetriesLimit()); + + pathService = new FlowPathService(this); + syncService = new FlowSyncService(this, persistenceManager, resourcesManager, pathOperationConfig); + + carrierContext = new CarrierContext<>(); + } + + @Override + public void declareOutputFields(OutputFieldsDeclarer declarer) { + super.declareOutputFields(declarer); + + declarer.declareStream(ZkStreams.ZK.toString(), + new Fields(ZooKeeperBolt.FIELD_ID_STATE, ZooKeeperBolt.FIELD_ID_CONTEXT)); + + declarer.declareStream(HUB_TO_SPEAKER_WORKER.name(), MessageKafkaTranslator.STREAM_FIELDS); + declarer.declareStream(HUB_TO_NB_RESPONSE_SENDER.name(), MessageKafkaTranslator.STREAM_FIELDS); + declarer.declareStream(HUB_TO_HISTORY_TOPOLOGY_SENDER.name(), MessageKafkaTranslator.STREAM_FIELDS); + declarer.declareStream(HUB_TO_PING_SENDER.name(), MessageKafkaTranslator.STREAM_FIELDS); + declarer.declareStream(HUB_TO_FLOW_MONITORING_TOPOLOGY_SENDER.name(), MessageKafkaTranslator.STREAM_FIELDS); + declarer.declareStream(HUB_TO_STATS_TOPOLOGY_SENDER.name(), MessageKafkaTranslator.STREAM_FIELDS); + } + + // -- topology API -- + + @Getter + public static class FlowSyncConfig extends Config { + private final int speakerCommandRetriesLimit; + + @Builder(builderMethodName = "flowSyncBuilder", builderClassName = "flowSyncBuild") + public FlowSyncConfig( + String requestSenderComponent, String workerComponent, String lifeCycleEventComponent, int timeoutMs, + boolean autoAck, int speakerCommandRetriesLimit) { + super(requestSenderComponent, workerComponent, lifeCycleEventComponent, timeoutMs, autoAck); + this.speakerCommandRetriesLimit = speakerCommandRetriesLimit; + } + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/RouterBolt.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/RouterBolt.java index a930a2a0570..df822d420c2 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/RouterBolt.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/bolts/RouterBolt.java @@ -24,6 +24,7 @@ import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.ROUTER_TO_FLOW_PATH_SWAP_HUB; import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.ROUTER_TO_FLOW_REROUTE_HUB; import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.ROUTER_TO_FLOW_SWAP_ENDPOINTS_HUB; +import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.ROUTER_TO_FLOW_SYNC_HUB; import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.ROUTER_TO_FLOW_UPDATE_HUB; import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.ROUTER_TO_FLOW_VALIDATION_HUB; import static org.openkilda.wfm.topology.flowhs.FlowHsTopology.Stream.ROUTER_TO_YFLOW_CREATE_HUB; @@ -46,6 +47,7 @@ import org.openkilda.messaging.command.flow.FlowPathSwapRequest; import org.openkilda.messaging.command.flow.FlowRequest; import org.openkilda.messaging.command.flow.FlowRerouteRequest; +import org.openkilda.messaging.command.flow.FlowSyncRequest; import org.openkilda.messaging.command.flow.FlowValidationRequest; import org.openkilda.messaging.command.flow.SwapFlowEndpointRequest; import org.openkilda.messaging.command.yflow.SubFlowsReadRequest; @@ -74,6 +76,7 @@ public class RouterBolt extends AbstractBolt { public static final String FLOW_ID_FIELD = "flow-id"; + private static final Fields STREAM_FIELDS = new Fields(FIELD_ID_KEY, FLOW_ID_FIELD, FIELD_ID_PAYLOAD, FIELD_ID_CONTEXT); @@ -123,6 +126,8 @@ protected void handleInput(Tuple input) { key, input.getMessageId()); Values values = new Values(key, deleteRequest.getFlowId(), data); emitWithContext(ROUTER_TO_FLOW_DELETE_HUB.name(), input, values); + } else if (data instanceof FlowSyncRequest) { + routeSyncRequest(input, (FlowSyncRequest) data, key); } else if (data instanceof FlowPathSwapRequest) { FlowPathSwapRequest pathSwapRequest = (FlowPathSwapRequest) data; log.debug("Received a path swap request {} with key {}. MessageId {}", pathSwapRequest.getFlowId(), @@ -221,6 +226,13 @@ protected void handleInput(Tuple input) { } } + private void routeSyncRequest(Tuple input, FlowSyncRequest syncRequest, String key) { + log.debug("Received a sync request {} with key {}. MessageId {}", + syncRequest.getFlowId(), key, input.getMessageId()); + Values values = new Values(key, syncRequest.getFlowId(), syncRequest, getCommandContext()); + emit(ROUTER_TO_FLOW_SYNC_HUB.name(), input, values); + } + @Override public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declareStream(ROUTER_TO_FLOW_CREATE_HUB.name(), STREAM_FIELDS); @@ -230,6 +242,7 @@ public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declareStream(ROUTER_TO_FLOW_PATH_SWAP_HUB.name(), STREAM_FIELDS); declarer.declareStream(ROUTER_TO_FLOW_CREATE_MIRROR_POINT_HUB.name(), STREAM_FIELDS); declarer.declareStream(ROUTER_TO_FLOW_DELETE_MIRROR_POINT_HUB.name(), STREAM_FIELDS); + declarer.declareStream(ROUTER_TO_FLOW_SYNC_HUB.name(), STREAM_FIELDS); declarer.declareStream(ROUTER_TO_FLOW_SWAP_ENDPOINTS_HUB.name(), new Fields(FIELD_ID_KEY, FIELD_ID_PAYLOAD, FIELD_ID_CONTEXT)); declarer.declareStream(ROUTER_TO_FLOW_VALIDATION_HUB.name(), STREAM_FIELDS); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/FsmUtil.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/FsmUtil.java new file mode 100644 index 00000000000..8bc11ff8151 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/FsmUtil.java @@ -0,0 +1,54 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm; + +import org.openkilda.wfm.share.metrics.MeterRegistryHolder; + +import io.micrometer.core.instrument.LongTaskTimer; +import io.micrometer.core.instrument.LongTaskTimer.Sample; +import org.squirrelframework.foundation.fsm.StateMachine; + +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public final class FsmUtil { + /** + * Add FSM execution time metric. + */ + public static void addExecutionTimeMeter( + StateMachine subject, Supplier resultSupplier) { + MeterRegistryHolder.getRegistry().ifPresent(registry -> { + // TODO(surabujin): should the name be FSM specific? + Sample sample = LongTaskTimer.builder("fsm.active_execution") + .register(registry) + .start(); + subject.addTerminateListener(e -> { + long duration = sample.stop(); + + String name = "fsm.execution." + Optional.ofNullable(resultSupplier.get()) + .map(result -> result ? "success" : "failed") + .orElse("undefined"); + registry.timer(name) + .record(duration, TimeUnit.NANOSECONDS); + }); + }); + } + + private FsmUtil() { + // hide public constructor + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java index 14ab89d33a3..b475fd72439 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java @@ -23,6 +23,7 @@ import org.openkilda.wfm.share.history.model.FlowHistoryData; import org.openkilda.wfm.share.history.model.FlowHistoryHolder; import org.openkilda.wfm.share.utils.KeyProvider; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHistoryCarrier; import org.openkilda.wfm.topology.flowhs.service.common.HistoryUpdateCarrier; import org.openkilda.wfm.topology.flowhs.service.common.NorthboundResponseCarrier; import org.openkilda.wfm.topology.flowhs.service.common.ProcessingEventListener; @@ -35,7 +36,8 @@ public abstract class FlowProcessingWithHistorySupportFsm, S, E, C, R extends NorthboundResponseCarrier & HistoryUpdateCarrier, L extends ProcessingEventListener> - extends NbTrackableFlowProcessingFsm { + extends NbTrackableFlowProcessingFsm + implements FlowHistoryCarrier { private Instant lastHistoryEntryTime; protected FlowProcessingWithHistorySupportFsm(@NonNull E nextEvent, @NonNull E errorEvent, @@ -57,9 +59,7 @@ public void saveActionToHistory(String action) { sendHistoryData(action, null); } - /** - * Add a history record on the action. - */ + @Override public void saveActionToHistory(String action, String description) { log.debug("Flow {} action - {} : {}", getFlowId(), action, description); sendHistoryData(action, description); @@ -83,17 +83,13 @@ public void saveFlowActionToHistory(String flowId, String action, String descrip sendHistoryData(flowId, action, description, taskId); } - /** - * Add a history record on the error. - */ + @Override public void saveErrorToHistory(String action, String errorMessage) { log.error("Flow {} error - {} : {}", getFlowId(), action, errorMessage); sendHistoryData(action, errorMessage); } - /** - * Add a history record on the error. - */ + @Override public void saveErrorToHistory(String errorMessage) { log.error("Flow {} error - {}", getFlowId(), errorMessage); sendHistoryData(errorMessage, null); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/DummyFlowPathHistoryFormatter.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/DummyFlowPathHistoryFormatter.java new file mode 100644 index 00000000000..1cea1fc0197 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/DummyFlowPathHistoryFormatter.java @@ -0,0 +1,60 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; + +import java.util.List; + +class DummyFlowPathHistoryFormatter extends FlowPathHistoryFormatter { + private static final String ERROR_MESSAGE = "Dummy history formatter have been used"; + + public DummyFlowPathHistoryFormatter() { + super(null); + } + + @Override + public void recordChunkProcessing(PathChunkType type) { + throw new IllegalStateException(ERROR_MESSAGE); + } + + @Override + public void recordSegmentSuccess( + PathChunkType type, FlowSegmentRequest request, SpeakerFlowSegmentResponse response) { + throw new IllegalStateException(ERROR_MESSAGE); + + } + + @Override + public void recordSegmentFailureAndRetry( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse, int attempt) { + throw new IllegalStateException(ERROR_MESSAGE); + } + + @Override + public void recordSegmentFailureAndGiveUp( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse) { + throw new IllegalStateException(ERROR_MESSAGE); + } + + @Override + public void recordChunkFailure(PathChunkType type, List failRequests) { + throw new IllegalStateException(ERROR_MESSAGE); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortInstallHistoryFormatter.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortInstallHistoryFormatter.java new file mode 100644 index 00000000000..0eee8b85845 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortInstallHistoryFormatter.java @@ -0,0 +1,67 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHistoryCarrier; + +import java.util.List; + +class FlowPathAbortInstallHistoryFormatter extends FlowPathHistoryFormatter { + public FlowPathAbortInstallHistoryFormatter(FlowHistoryCarrier carrier) { + super(carrier); + } + + @Override + public void recordChunkProcessing(PathChunkType type) { + carrier.saveActionToHistory("Started removing of possibly installed rules", null); + } + + @Override + public void recordSegmentSuccess( + PathChunkType type, FlowSegmentRequest request, SpeakerFlowSegmentResponse response) { + carrier.saveActionToHistory( + "Rule was deleted", String.format( + "The rule was removed: switch %s, cookie %s", + response.getSwitchId(), request.getCookie())); + } + + @Override + public void recordSegmentFailureAndRetry( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse, int attempt) { + carrier.saveErrorToHistory("Failed to remove rule", String.format( + "Failed to remove the %s rule: commandId %s, switch %s, cookie %s. Error %s. Retrying (attempt %d)", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse, + attempt)); + } + + @Override + public void recordSegmentFailureAndGiveUp( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse) { + carrier.saveErrorToHistory("Failed to remove rule", String.format( + "Failed to remove the rule: commandId %s, switch %s, cookie %s. Error: %s", + request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse)); + } + + @Override + public void recordChunkFailure(PathChunkType type, List failRequests) { + carrier.saveErrorToHistory(String.format( + "Received error response(s) for %d remove / re-install commands", failRequests.size())); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortRemoveHistoryFormatter.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortRemoveHistoryFormatter.java new file mode 100644 index 00000000000..5c44878e339 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathAbortRemoveHistoryFormatter.java @@ -0,0 +1,67 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHistoryCarrier; + +import java.util.List; + +class FlowPathAbortRemoveHistoryFormatter extends FlowPathHistoryFormatter { + public FlowPathAbortRemoveHistoryFormatter(FlowHistoryCarrier carrier) { + super(carrier); + } + + @Override + public void recordChunkProcessing(PathChunkType type) { + carrier.saveActionToHistory("Started installing of possibly removed rules", null); + } + + @Override + public void recordSegmentSuccess( + PathChunkType type, FlowSegmentRequest request, SpeakerFlowSegmentResponse response) { + carrier.saveActionToHistory( + "Rule was restored", String.format( + "The rule was installed: switch %s, cookie %s", + response.getSwitchId(), request.getCookie())); + } + + @Override + public void recordSegmentFailureAndRetry( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse, int attempt) { + carrier.saveErrorToHistory("Failed to restore rule", String.format( + "Failed to restore the %s rule: commandId %s, switch %s, cookie %s. Error %s. Retrying (attempt %d)", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse, + attempt)); + } + + @Override + public void recordSegmentFailureAndGiveUp( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse) { + carrier.saveErrorToHistory("Failed to restore rule", String.format( + "Failed to restore the rule: commandId %s, switch %s, cookie %s. Error: %s", + request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse)); + } + + @Override + public void recordChunkFailure(PathChunkType type, List failRequests) { + carrier.saveErrorToHistory(String.format( + "Received error response(s) for %d install/restore commands", failRequests.size())); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathContext.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathContext.java new file mode 100644 index 00000000000..0b11d6ba2ab --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathContext.java @@ -0,0 +1,27 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class FlowPathContext { + SpeakerFlowSegmentResponse speakerResponse; +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathFsmBase.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathFsmBase.java new file mode 100644 index 00000000000..7b6a6c09d54 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathFsmBase.java @@ -0,0 +1,285 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.request.factory.FlowSegmentRequestFactory; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.topology.flowhs.fsm.FsmUtil; +import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithHistorySupportFsm; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathChunk; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathReference; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResult; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; +import org.openkilda.wfm.topology.flowhs.service.FlowGenericCarrier; +import org.openkilda.wfm.topology.flowhs.service.common.ProcessingEventListener; + +import com.fasterxml.uuid.Generators; +import com.fasterxml.uuid.NoArgGenerator; +import lombok.Getter; +import lombok.NonNull; +import org.squirrelframework.foundation.fsm.StateMachine; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +// TODO(surabujin): reconsider inheritance from FlowProcessingWithHistorySupportFsm +// TODO(surabujin): request round trip timer +public abstract class FlowPathFsmBase< + T extends StateMachine> + extends FlowProcessingWithHistorySupportFsm< + T, FlowPathFsmBase.State, FlowPathFsmBase.Event, FlowPathContext, FlowGenericCarrier, ProcessingEventListener> + implements FlowPathOperation { + protected final NoArgGenerator commandIdGenerator = Generators.timeBasedGenerator(); + + protected final FlowPathOperationConfig config; + protected final FlowPathRequest subject; + + @Getter + protected final CompletableFuture resultFuture = new CompletableFuture<>(); + + @Getter + private FlowPathResultCode resultCode; + + protected FlowPathChunk currentChunk; + protected final List chunksToProcess; + protected final List completedChunks = new ArrayList<>(); + + protected FlowPathHistoryFormatter historyFormatter = new DummyFlowPathHistoryFormatter(); + + private final Map pendingRequests = new HashMap<>(); + private final List failedRequests = new ArrayList<>(); + private int failedRequestsBase = 0; + + public FlowPathFsmBase( + @NonNull FlowPathOperationConfig config, @NonNull FlowPathRequest subject, + @NonNull FlowGenericCarrier carrier, @NonNull CommandContext commandContext) { + super(Event.NEXT, Event.ERROR, commandContext, carrier); + + this.config = config; + this.subject = subject; + + chunksToProcess = new ArrayList<>(subject.getPathChunks()); + } + + // -- public API -- + + @Override + public String getFlowId() { + return getPathReference().getFlowId(); + } + + @Override + protected String getCrudActionName() { + return "path-install"; + } + + @Override + public FlowPathReference getPathReference() { + return subject.getReference(); + } + + @Override + public void handleSpeakerResponse(@NonNull SpeakerFlowSegmentResponse response) { + FlowPathContext context = FlowPathContext.builder() + .speakerResponse(response) + .build(); + handleEvent(Event.SPEAKER_RESPONSE, context); + } + + @Override + public void handleCancel() { + FlowPathContext context = FlowPathContext.builder().build(); + handleEvent(Event.CANCEL, context); + } + + // -- private/service methods -- + + protected Optional processCurrentChunk( + Function requestFactoryAdapter) { + for (FlowSegmentRequestFactory entry : currentChunk.getPayload()) { + PendingEntry pendingEntry = new PendingEntry(entry, requestFactoryAdapter, currentChunk.getType()); + emitRequest(pendingEntry); + } + historyFormatter.recordChunkProcessing(currentChunk.getType()); + + if (pendingRequests.isEmpty()) { + return Optional.of(Event.CHUNK_COMPLETE); + } + + return Optional.empty(); + } + + protected Optional processSpeakerResponse(SpeakerFlowSegmentResponse response) { + PendingEntry pendingEntry = pendingRequests.remove(response.getCommandId()); + if (pendingEntry == null) { + log.error("Received a response for unexpected command: {}", response); + return Optional.empty(); + } + + if (response instanceof FlowErrorResponse) { + return processSpeakerResponse((FlowErrorResponse) response, pendingEntry); + } else { + return processSpeakerResponse(response, pendingEntry); + } + } + + protected Optional processSpeakerResponse(SpeakerFlowSegmentResponse response, PendingEntry pendingEntry) { + historyFormatter.recordSegmentSuccess(currentChunk.getType(), pendingEntry.getRequest(), response); + return chooseTransitionEventIfChunkCompleted(); + } + + protected Optional processSpeakerResponse(FlowErrorResponse response, PendingEntry previous) { + PendingEntry current = PendingEntry.newAttempt(previous); + if (config.getSpeakerCommandRetriesLimit() < current.getAttempt()) { + historyFormatter.recordSegmentFailureAndGiveUp(currentChunk.getType(), previous.getRequest(), response); + failedRequests.add(previous); + } else { + historyFormatter.recordSegmentFailureAndRetry( + currentChunk.getType(), previous.getRequest(), response, current.getAttempt()); + emitRequest(current); + } + return chooseTransitionEventIfChunkCompleted(); + } + + protected Optional chooseTransitionEventIfChunkCompleted() { + if (!pendingRequests.isEmpty()) { + return Optional.empty(); + } + + List failRequests = getFailedRequestsForCurrentChunk() + .stream() + .map(PendingEntry::getRequest) + .collect(Collectors.toList()); + if (!failRequests.isEmpty()) { + historyFormatter.recordChunkFailure(currentChunk.getType(), failRequests); + return Optional.of(Event.ERROR); + } else { + return Optional.of(Event.CHUNK_COMPLETE); + } + } + + protected FlowPathChunk buildRevertChunk() { + List payload = new ArrayList<>(); + for (FlowPathChunk entry : completedChunks) { + payload.addAll(entry.getPayload()); + } + if (currentChunk != null) { + payload.addAll(currentChunk.getPayload()); + } + + return new FlowPathChunk(PathChunkType.REVERT, payload); + } + + protected boolean swapChunk() { + if (chunksToProcess.isEmpty()) { + return false; + } + + if (currentChunk != null) { + completedChunks.add(currentChunk); + } + currentChunk = chunksToProcess.remove(0); + + pendingRequests.clear(); + failedRequestsBase = failedRequests.size(); + + return true; + } + + protected void emitRequest(PendingEntry pendingEntry) { + FlowSegmentRequest request = pendingEntry.getRequest(); + UUID requestId = request.getCommandId(); + + log.info( + "Emit speaker flow segment {} {} request to the switch={} cookie={} pathId={} attempt={}", + pendingEntry.getType(), detectFlowSegmentRequestType(request), request.getSwitchId(), + request.getCookie(), subject.getReference().getPathId(), pendingEntry.getAttempt()); + getCarrier().sendSpeakerRequest(request); + pendingRequests.put(requestId, pendingEntry); + } + + protected void handleEvent(Supplier> eventSupplier, FlowPathContext context) { + eventSupplier.get() + .ifPresent(event -> handleEvent(event, context)); + } + + protected abstract void handleEvent(Event event, FlowPathContext context); + + protected void handleTermination() { + resultFuture.complete(new FlowPathResult(getPathReference(), resultCode)); + } + + protected List getFailedRequestsForCurrentChunk() { + return failedRequests.subList(failedRequestsBase, failedRequests.size()); + } + + protected void setResultCode(FlowPathResultCode code) { + if (resultCode == null) { + resultCode = code; + } else { + log.debug("Do not replace result code with {}, current value {}", code, resultCode); + } + } + + private static String detectFlowSegmentRequestType(FlowSegmentRequest request) { + String result; + if (request.isInstallRequest()) { + result = "INSTALL"; + } else if (request.isVerifyRequest()) { + result = "VERIFY"; + } else if (request.isRemoveRequest()) { + result = "REMOVE"; + } else { + result = "(unknown)"; + } + return result; + } + + protected void initFsm() { + addTerminateListener(dummy -> handleTermination()); + FsmUtil.addExecutionTimeMeter(this, () -> getResultCode() == FlowPathResultCode.SUCCESS); + + FlowPathContext context = FlowPathContext.builder().build(); + start(context); + } + + enum State { + INSTALL, DELETE, VERIFY, + WAIT_PENDING, REVERT_WAIT_PENDING, REVERT, + END + } + + enum Event { + NEXT, ERROR, + SPEAKER_RESPONSE, CANCEL, + + CHUNK_COMPLETE, NO_MORE_CHUNKS + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathHistoryFormatter.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathHistoryFormatter.java new file mode 100644 index 00000000000..2b85857a06d --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathHistoryFormatter.java @@ -0,0 +1,46 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHistoryCarrier; + +import java.util.List; + +abstract class FlowPathHistoryFormatter { + protected final FlowHistoryCarrier carrier; + + public FlowPathHistoryFormatter(FlowHistoryCarrier carrier) { + this.carrier = carrier; + } + + public abstract void recordChunkProcessing(FlowPathRequest.PathChunkType type); + + public abstract void recordSegmentSuccess( + PathChunkType type, FlowSegmentRequest request, SpeakerFlowSegmentResponse response); + + public abstract void recordSegmentFailureAndRetry( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse, int attempt); + + public abstract void recordSegmentFailureAndGiveUp( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse); + + public abstract void recordChunkFailure(PathChunkType type, List failRequests); +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallFsm.java new file mode 100644 index 00000000000..e10abe0ea25 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallFsm.java @@ -0,0 +1,175 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.utils.FsmExecutor; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; +import org.openkilda.wfm.topology.flowhs.service.FlowGenericCarrier; + +import lombok.NonNull; +import org.squirrelframework.foundation.fsm.StateMachineBuilder; +import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory; + +public class FlowPathInstallFsm extends FlowPathFsmBase { + private static final FsmExecutor EXECUTOR + = new FsmExecutor<>(Event.NEXT); + + public FlowPathInstallFsm( + @NonNull FlowPathOperationConfig config, @NonNull FlowPathRequest subject, + @NonNull FlowGenericCarrier carrier, @NonNull CommandContext commandContext) { + super(config, subject, carrier, commandContext); + } + + // -- FSM actions -- + + public void enterInstallAction(State from, State to, Event event, FlowPathContext context) { + historyFormatter = new FlowPathInstallHistoryFormatter(this); + + if (! swapChunk()) { + handleEvent(Event.NO_MORE_CHUNKS, context); + return; + } + + log.info("Installing {} path chunk ({} entries)", + currentChunk.getType(), currentChunk.getPayload().size()); + handleEvent( + () -> processCurrentChunk(factory -> factory.makeInstallRequest(commandIdGenerator.generate())), + context); + } + + public void enterVerifyAction(State from, State to, Event event, FlowPathContext context) { + historyFormatter = new FlowPathVerifyHistoryFormatter(this); + log.info("Verifying installed {} path chunk ({} entries)", + currentChunk.getType(), currentChunk.getPayload().size()); + + handleEvent( + () -> processCurrentChunk(factory -> factory.makeVerifyRequest(commandIdGenerator.generate())), + context); + } + + public void enterRevertAction(State from, State to, Event event, FlowPathContext context) { + if (! subject.isCanRevertOnError()) { + log.info("Do not perform path install revert operation (denied by request settings)"); + handleEvent(Event.CHUNK_COMPLETE, context); + return; + } + + historyFormatter = new FlowPathAbortInstallHistoryFormatter(this); + + currentChunk = buildRevertChunk(); + log.info("Reverting possible installed path segments ({} entries)", currentChunk.getPayload().size()); + + handleEvent( + () -> processCurrentChunk(factory -> factory.makeRemoveRequest(commandIdGenerator.generate())), + context); + } + + public void enterEndAction(State from, State to, Event event, FlowPathContext context) { + setResultCode(FlowPathResultCode.SUCCESS); + } + + public void speakerResponseAction(State from, State to, Event event, FlowPathContext context) { + handleEvent(() -> processSpeakerResponse(context.getSpeakerResponse()), context); + } + + public void markCanceledAction(State from, State to, Event event, FlowPathContext context) { + setResultCode(FlowPathResultCode.CANCEL); + } + + public void markSpeakerErrorAction(State from, State to, Event event, FlowPathContext context) { + setResultCode(FlowPathResultCode.SPEAKER_ERROR); + } + + // -- private/service methods -- + + @Override + protected void handleEvent(Event event, FlowPathContext context) { + EXECUTOR.fire(this, event, context); + } + + // -- FSM definition -- + + public static class Factory { + private final StateMachineBuilder builder; + private final FlowGenericCarrier carrier; + + public Factory(@NonNull FlowGenericCarrier carrier) { + builder = StateMachineBuilderFactory.create( + FlowPathInstallFsm.class, State.class, Event.class, FlowPathContext.class, + FlowPathOperationConfig.class, FlowPathRequest.class, FlowGenericCarrier.class, + CommandContext.class); + this.carrier = carrier; + + final String speakerResponseActionMethod = "speakerResponseAction"; + final String markCanceledActionMethod = "markCanceledAction"; + final String markSpeakerErrorActionMethod = "markSpeakerErrorAction"; + + // INSTALL + builder.onEntry(State.INSTALL) + .callMethod("enterInstallAction"); + builder.transition().from(State.INSTALL).to(State.REVERT).on(Event.ERROR) + .callMethod(markSpeakerErrorActionMethod); + builder.transition().from(State.INSTALL).to(State.REVERT_WAIT_PENDING).on(Event.CANCEL) + .callMethod(markCanceledActionMethod); + builder.transition().from(State.INSTALL).to(State.VERIFY).on(Event.CHUNK_COMPLETE); + builder.transition().from(State.INSTALL).to(State.END).on(Event.NO_MORE_CHUNKS); + builder.internalTransition().within(State.INSTALL).on(Event.SPEAKER_RESPONSE) + .callMethod(speakerResponseActionMethod); + + // VERIFY + builder.onEntry(State.VERIFY) + .callMethod("enterVerifyAction"); + builder.transition().from(State.VERIFY).to(State.REVERT).on(Event.ERROR) + .callMethod(markSpeakerErrorActionMethod); + builder.transition().from(State.VERIFY).to(State.REVERT_WAIT_PENDING).on(Event.CANCEL) + .callMethod(markCanceledActionMethod); + builder.transition().from(State.VERIFY).to(State.INSTALL).on(Event.CHUNK_COMPLETE); + builder.internalTransition().within(State.VERIFY).on(Event.SPEAKER_RESPONSE) + .callMethod(speakerResponseActionMethod); + + // REVERT_WAIT_PENDING + builder.transition().from(State.REVERT_WAIT_PENDING).to(State.END).on(Event.CHUNK_COMPLETE); + builder.transition().from(State.REVERT_WAIT_PENDING).to(State.END).on(Event.ERROR); + builder.internalTransition().within(State.REVERT_WAIT_PENDING).on(Event.SPEAKER_RESPONSE) + .callMethod(speakerResponseActionMethod); + + // REVERT + builder.onEntry(State.REVERT) + .callMethod("enterRevertAction"); + builder.transition().from(State.REVERT).to(State.END).on(Event.CHUNK_COMPLETE); + builder.transition().from(State.REVERT).to(State.END).on(Event.ERROR); + builder.internalTransition().within(State.REVERT).on(Event.SPEAKER_RESPONSE) + .callMethod(speakerResponseActionMethod); + + // END + builder.onEntry(State.END) + .callMethod("enterEndAction"); + + builder.defineFinalState(State.END); + } + + public FlowPathInstallFsm newInstance( + @NonNull FlowPathOperationConfig config, + @NonNull FlowPathRequest subject, @NonNull CommandContext commandContext) { + FlowPathInstallFsm fsm = builder.newStateMachine(State.INSTALL, config, subject, carrier, commandContext); + fsm.initFsm(); + return fsm; + } + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallHistoryFormatter.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallHistoryFormatter.java new file mode 100644 index 00000000000..d2d03a7803a --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathInstallHistoryFormatter.java @@ -0,0 +1,70 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHistoryCarrier; + +import java.util.List; + +class FlowPathInstallHistoryFormatter extends FlowPathHistoryFormatter { + public FlowPathInstallHistoryFormatter(FlowHistoryCarrier carrier) { + super(carrier); + } + + @Override + public void recordChunkProcessing(PathChunkType type) { + carrier.saveActionToHistory(String.format("Commands for installing %s rules have been sent", type), null); + } + + @Override + public void recordSegmentSuccess( + PathChunkType type, FlowSegmentRequest request, SpeakerFlowSegmentResponse response) { + carrier.saveActionToHistory( + "Rule was installed", String.format( + "The %s rule was installed: switch %s, cookie %s", + type, response.getSwitchId(), request.getCookie())); + } + + @Override + public void recordSegmentFailureAndRetry( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse, int attempt) { + carrier.saveErrorToHistory( + "Failed to install rule", String.format( + "Failed to install %s rule: commandId %s, switch %s, cookie %s. Error %s. Retrying " + + "(attempt %d)", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse, + attempt)); + } + + @Override + public void recordSegmentFailureAndGiveUp( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse) { + carrier.saveErrorToHistory( + "Failed to install rule", String.format( + "Failed to install %s rule: commandId %s, switch %s, cookie %s. Error: %s", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse)); + } + + @Override + public void recordChunkFailure(PathChunkType type, List failRequests) { + carrier.saveErrorToHistory(String.format( + "Received error response(s) for %d install commands related to %s chunk", failRequests.size(), type)); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathOperation.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathOperation.java new file mode 100644 index 00000000000..ee28cf64b56 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathOperation.java @@ -0,0 +1,37 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathReference; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResult; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; + +import lombok.NonNull; + +import java.util.concurrent.CompletableFuture; + +public interface FlowPathOperation { + void handleSpeakerResponse(@NonNull SpeakerFlowSegmentResponse response); + + void handleCancel(); + + FlowPathReference getPathReference(); + + FlowPathResultCode getResultCode(); + + CompletableFuture getResultFuture(); +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveFsm.java new file mode 100644 index 00000000000..66c1080e6de --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveFsm.java @@ -0,0 +1,163 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.utils.FsmExecutor; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; +import org.openkilda.wfm.topology.flowhs.service.FlowGenericCarrier; + +import lombok.NonNull; +import org.squirrelframework.foundation.fsm.StateMachineBuilder; +import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory; + +public class FlowPathRemoveFsm extends FlowPathFsmBase { + private static final FsmExecutor EXECUTOR + = new FsmExecutor<>(Event.NEXT); + + public FlowPathRemoveFsm( + @NonNull FlowPathOperationConfig config, @NonNull FlowPathRequest subject, + @NonNull FlowGenericCarrier carrier, @NonNull CommandContext commandContext) { + super(config, subject, carrier, commandContext); + } + + // -- FSM actions -- + + public void enterRemoveAction(State from, State to, Event event, FlowPathContext context) { + historyFormatter = new FlowPathRemoveHistoryFormatter(this); + + if (!swapChunk()) { + handleEvent(Event.NO_MORE_CHUNKS, context); + return; + } + + log.info("Removing {} path chunk ({} entries)", + currentChunk.getType(), currentChunk.getPayload().size()); + handleEvent( + processCurrentChunk(factory -> factory.makeRemoveRequest(commandIdGenerator.generate())) + .orElse(Event.NEXT), + context); + } + + public void enterRevertAction(State from, State to, Event event, FlowPathContext context) { + if (! subject.isCanRevertOnError()) { + log.info("Do not perform path remove revert operation (denied by request settings)"); + handleEvent(Event.CHUNK_COMPLETE, context); + return; + } + + historyFormatter = new FlowPathAbortRemoveHistoryFormatter(this); + + currentChunk = buildRevertChunk(); + log.info("Reverting possible removed path segments ({} entries)", currentChunk.getPayload().size()); + + handleEvent( + () -> processCurrentChunk(factory -> factory.makeInstallRequest(commandIdGenerator.generate())), + context); + } + + public void enterEndAction(State from, State to, Event event, FlowPathContext context) { + setResultCode(FlowPathResultCode.SUCCESS); + } + + public void speakerResponseAction(State from, State to, Event event, FlowPathContext context) { + handleEvent(() -> processSpeakerResponse(context.getSpeakerResponse()), context); + } + + public void markCanceledAction(State from, State to, Event event, FlowPathContext context) { + setResultCode(FlowPathResultCode.CANCEL); + } + + public void markSpeakerErrorAction(State from, State to, Event event, FlowPathContext context) { + setResultCode(FlowPathResultCode.SPEAKER_ERROR); + } + + // -- private/service methods -- + + @Override + protected void handleEvent(Event event, FlowPathContext context) { + EXECUTOR.fire(this, event, context); + } + + // -- FSM definition -- + + public static class Factory { + private final StateMachineBuilder builder; + private final FlowGenericCarrier carrier; + + public Factory(@NonNull FlowGenericCarrier carrier) { + builder = StateMachineBuilderFactory.create( + FlowPathRemoveFsm.class, State.class, Event.class, FlowPathContext.class, + FlowPathOperationConfig.class, FlowPathRequest.class, FlowGenericCarrier.class, + CommandContext.class); + this.carrier = carrier; + + final String speakerResponseActionMethod = "speakerResponseAction"; + final String markCanceledActionMethod = "markCanceledAction"; + final String markSpeakerErrorActionMethod = "markSpeakerErrorAction"; + + // DELETE + builder.onEntry(State.DELETE) + .callMethod("enterRemoveAction"); + builder.transition().from(State.DELETE).to(State.WAIT_PENDING).on(Event.NEXT); + builder.transition().from(State.DELETE).to(State.REVERT).on(Event.ERROR) + .callMethod(markSpeakerErrorActionMethod); + builder.transition().from(State.DELETE).to(State.REVERT_WAIT_PENDING).on(Event.CANCEL) + .callMethod(markCanceledActionMethod); + builder.transition().from(State.DELETE).to(State.END).on(Event.CHUNK_COMPLETE); + builder.transition().from(State.DELETE).to(State.END).on(Event.NO_MORE_CHUNKS); + + // WAIT_PENDING + builder.transition().from(State.WAIT_PENDING).to(State.REVERT).on(Event.ERROR) + .callMethod(markSpeakerErrorActionMethod); + builder.transition().from(State.WAIT_PENDING).to(State.REVERT_WAIT_PENDING).on(Event.CANCEL) + .callMethod(markCanceledActionMethod); + builder.transition().from(State.WAIT_PENDING).to(State.DELETE).on(Event.CHUNK_COMPLETE); + builder.internalTransition().within(State.WAIT_PENDING).on(Event.SPEAKER_RESPONSE) + .callMethod(speakerResponseActionMethod); + + // REVERT_WAIT_PENDING + builder.transition().from(State.REVERT_WAIT_PENDING).to(State.REVERT).on(Event.ERROR); + builder.transition().from(State.REVERT_WAIT_PENDING).to(State.REVERT).on(Event.CHUNK_COMPLETE); + builder.internalTransition().within(State.REVERT_WAIT_PENDING).on(Event.SPEAKER_RESPONSE) + .callMethod(speakerResponseActionMethod); + + // REVERT + builder.onEntry(State.REVERT) + .callMethod("enterRevertAction"); + builder.transition().from(State.REVERT).to(State.END).on(Event.ERROR); + builder.transition().from(State.REVERT).to(State.END).on(Event.CHUNK_COMPLETE); + builder.internalTransition().within(State.REVERT).on(Event.SPEAKER_RESPONSE) + .callMethod(speakerResponseActionMethod); + + // END + builder.onEntry(State.END) + .callMethod("enterEndAction"); + + builder.defineFinalState(State.END); + } + + public FlowPathRemoveFsm newInstance( + @NonNull FlowPathOperationConfig config, + @NonNull FlowPathRequest subject, @NonNull CommandContext commandContext) { + FlowPathRemoveFsm fsm = builder.newStateMachine(State.DELETE, config, subject, carrier, commandContext); + fsm.initFsm(); + return fsm; + } + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveHistoryFormatter.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveHistoryFormatter.java new file mode 100644 index 00000000000..11e2c656a27 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathRemoveHistoryFormatter.java @@ -0,0 +1,70 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHistoryCarrier; + +import java.util.List; + +class FlowPathRemoveHistoryFormatter extends FlowPathHistoryFormatter { + public FlowPathRemoveHistoryFormatter(FlowHistoryCarrier carrier) { + super(carrier); + } + + @Override + public void recordChunkProcessing(PathChunkType type) { + carrier.saveActionToHistory(String.format("Commands for removing %s rules have been sent", type), null); + } + + @Override + public void recordSegmentSuccess( + PathChunkType type, FlowSegmentRequest request, SpeakerFlowSegmentResponse response) { + carrier.saveActionToHistory( + "Rule was removed", String.format( + "The %s rule was removed: switch %s, cookie %s", + type, response.getSwitchId(), request.getCookie())); + } + + @Override + public void recordSegmentFailureAndRetry( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse, int attempt) { + carrier.saveErrorToHistory( + "Failed to remove rule", String.format( + "Failed to remove %s rule: commandId %s, switch %s, cookie %s. Error %s. Retrying " + + "(attempt %d)", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse, + attempt)); + } + + @Override + public void recordSegmentFailureAndGiveUp( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse) { + carrier.saveErrorToHistory( + "Failed to remove rule", String.format( + "Failed to remove %s rule: commandId %s, switch %s, cookie %s. Error: %s", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse)); + } + + @Override + public void recordChunkFailure(PathChunkType type, List failRequests) { + carrier.saveErrorToHistory(String.format( + "Received error response(s) for %d remove commands related to %s chunk", failRequests.size(), type)); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathVerifyHistoryFormatter.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathVerifyHistoryFormatter.java new file mode 100644 index 00000000000..a7660250a40 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/FlowPathVerifyHistoryFormatter.java @@ -0,0 +1,70 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHistoryCarrier; + +import java.util.List; + +class FlowPathVerifyHistoryFormatter extends FlowPathHistoryFormatter { + public FlowPathVerifyHistoryFormatter(FlowHistoryCarrier carrier) { + super(carrier); + } + + @Override + public void recordChunkProcessing(PathChunkType type) { + carrier.saveActionToHistory(String.format("Started validation of installed %s rules", type), null); + } + + @Override + public void recordSegmentSuccess( + PathChunkType type, FlowSegmentRequest request, SpeakerFlowSegmentResponse response) { + carrier.saveActionToHistory( + "Rule was validated", String.format( + "The %s rule has been validated successfully: switch %s, cookie %s", + type, request.getSwitchId(), request.getCookie())); + } + + @Override + public void recordSegmentFailureAndRetry( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse, int attempt) { + carrier.saveErrorToHistory( + "Rule validation failed", String.format( + "Failed to validate %s rule: commandId %s, switch %s, cookie %s. Error %s. " + + "Retrying (attempt %d)", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse, + attempt)); + } + + @Override + public void recordSegmentFailureAndGiveUp( + PathChunkType type, FlowSegmentRequest request, FlowErrorResponse errorResponse) { + carrier.saveErrorToHistory( + "Rule validation failed", String.format( + "Failed to validate %s rule: commandId %s, switch %s, cookie %s. Error %s", + type, request.getCommandId(), errorResponse.getSwitchId(), request.getCookie(), errorResponse)); + } + + @Override + public void recordChunkFailure(PathChunkType type, List failRequests) { + carrier.saveErrorToHistory(String.format( + "Received error response(s) for %d verify commands related to %s chunk", failRequests.size(), type)); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/PendingEntry.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/PendingEntry.java new file mode 100644 index 00000000000..2ce6e4407c8 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/path/PendingEntry.java @@ -0,0 +1,59 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.path; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.request.factory.FlowSegmentRequestFactory; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; + +import lombok.Value; + +import java.util.function.Function; + +@Value +class PendingEntry { + FlowSegmentRequestFactory requestFactory; + Function requestFactoryAdapter; + PathChunkType type; + + FlowSegmentRequest request; + + int attempt; + + static PendingEntry newAttempt(PendingEntry previous) { + return new PendingEntry( + previous.getRequestFactory(), previous.getRequestFactoryAdapter(), previous.getType(), + previous.getAttempt() + 1); + } + + public PendingEntry( + FlowSegmentRequestFactory requestFactory, + Function requestFactoryAdapter, PathChunkType type) { + this(requestFactory, requestFactoryAdapter, type, 1); + } + + private PendingEntry( + FlowSegmentRequestFactory requestFactory, + Function requestFactoryAdapter, + PathChunkType type, int attempt) { + this.requestFactory = requestFactory; + this.requestFactoryAdapter = requestFactoryAdapter; + this.type = type; + this.attempt = attempt; + + request = requestFactoryAdapter.apply(requestFactory); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncContext.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncContext.java new file mode 100644 index 00000000000..228e5e9d6e7 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncContext.java @@ -0,0 +1,33 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.sync; + +import org.openkilda.messaging.error.ErrorType; +import org.openkilda.model.PathId; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class FlowSyncContext { + ErrorType errorType; + String errorDetails; + + PathId pathId; + FlowPathResultCode pathResultCode; +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncFsm.java new file mode 100644 index 00000000000..73201dbfe60 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/FlowSyncFsm.java @@ -0,0 +1,294 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.sync; + +import org.openkilda.model.PathId; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; +import org.openkilda.wfm.share.utils.FsmExecutor; +import org.openkilda.wfm.topology.flowhs.exception.UnknownKeyException; +import org.openkilda.wfm.topology.flowhs.fsm.FsmUtil; +import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithHistorySupportFsm; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.Event; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.State; +import org.openkilda.wfm.topology.flowhs.fsm.sync.actions.CreateSyncHandlersAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.actions.FailedCompleteAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.actions.FlowSyncSetupAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.actions.PathOperationResponseAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.actions.SuccessCompleteAction; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationDescriptor; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; +import org.openkilda.wfm.topology.flowhs.service.FlowGenericCarrier; +import org.openkilda.wfm.topology.flowhs.service.FlowProcessingEventListener; +import org.openkilda.wfm.topology.flowhs.service.FlowSyncCarrier; + +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.squirrelframework.foundation.fsm.StateMachineBuilder; +import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +@Slf4j +public class FlowSyncFsm + extends FlowProcessingWithHistorySupportFsm< + FlowSyncFsm, State, Event, FlowSyncContext, FlowSyncCarrier, FlowProcessingEventListener> { + public static final FsmExecutor EXECUTOR = new FsmExecutor<>( + Event.NEXT); + + @Getter + private final CompletableFuture resultFuture = new CompletableFuture<>(); + + private final Map pendingPathOperations = new HashMap<>(); + + @Getter + private final List pathOperationSuccess = new ArrayList<>(); + @Getter + private final List pathOperationFail = new ArrayList<>(); + + @Getter + private final String flowId; + + /** + * Indicator of dangerous sync operation. + * + *

If sync operation is dangerous customer traffic can be interrupted during installation of flow segments. + * Also, if path operation fails to install all path segments, target flow most probably will become corrupted - + * can't carry customer traffic. And one more side effect of such dangerous operation - in some cases extra rules on + * the switches used by target flow can appear after dangerous sync.

+ */ + @Getter @Setter + private boolean dangerousSync = false; + + public FlowSyncFsm( + @NonNull CommandContext commandContext, @NonNull FlowSyncCarrier carrier, @NonNull String flowId) { + super(Event.NEXT, Event.ERROR, commandContext, carrier); + this.flowId = flowId; + } + + // -- public API -- + + public void handlePathOperationResult(PathId pathId, FlowPathResultCode resultCode) { + handleEvent(Event.PATH_OPERATION_RESPONSE, FlowSyncContext.builder() + .pathId(pathId) + .pathResultCode(resultCode) + .build()); + } + + public void handleTimeout() { + handleEvent(Event.TIMEOUT, FlowSyncContext.builder().build()); + } + + public boolean isPendingPathOperationsExists() { + return ! pendingPathOperations.isEmpty(); + } + + public void addPendingPathOperation(FlowPathOperationDescriptor descriptor) { + pendingPathOperations.put(descriptor.getPathId(), descriptor); + } + + public Optional addSuccessPathOperation(PathId pathId) { + return commitFlowPathOperation(pathOperationSuccess, pathId); + } + + public Optional addFailedPathOperation(PathId pathId) { + return commitFlowPathOperation(pathOperationFail, pathId); + } + + // -- FSM actions -- + + public void enterCancelAction(State from, State to, Event event, FlowSyncContext context) { + for (PathId entry : pendingPathOperations.keySet()) { + log.info("Cancel path sync(install) operation for {} (flowId={})", entry, flowId); + try { + getCarrier().cancelFlowPathOperation(entry); + } catch (UnknownKeyException e) { + log.error("Path {} sync operation is missing (flowId={})", entry, flowId); + addFailedPathOperation(entry); + } + } + + checkPendingOperations(context); + } + + public void checkPendingOperationsAction(State from, State to, Event event, FlowSyncContext context) { + checkPendingOperations(context); + } + + public void reportGlobalTimeoutAction(State from, State to, Event event, FlowSyncContext context) { + saveGlobalTimeoutToHistory(); + } + + // -- private/service methods -- + + private void checkPendingOperations(FlowSyncContext context) { + if (! isPendingPathOperationsExists()) { + handleEvent(Event.GUARD_PASSED, context); + } + } + + protected void handleEvent(Event event, FlowSyncContext context) { + EXECUTOR.fire(this, event, context); + } + + private void onComplete() { + resultFuture.complete(null); + } + + private Optional commitFlowPathOperation( + List target, PathId pathId) { + FlowPathOperationDescriptor descriptor = pendingPathOperations.remove(pathId); + if (descriptor == null) { + return Optional.empty(); + } + + target.add(descriptor); + return Optional.of(descriptor); + } + + @Override + protected String getCrudActionName() { + return "sync"; + } + + // -- FSM definition -- + + public static class Factory { + private final StateMachineBuilder builder; + private final FlowGenericCarrier carrier; + + public Factory( + @NonNull FlowSyncCarrier carrier, @NonNull PersistenceManager persistenceManager, + @NonNull FlowResourcesManager resourcesManager, + @NonNull FlowPathOperationConfig flowPathOperationConfig) { + this.carrier = carrier; + + builder = StateMachineBuilderFactory.create( + FlowSyncFsm.class, State.class, Event.class, FlowSyncContext.class, + CommandContext.class, FlowSyncCarrier.class, String.class); + + final FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + + final PathOperationResponseAction pathOperationResponseAction = new PathOperationResponseAction( + persistenceManager); + final String reportGlobalTimeoutActionMethod = "reportGlobalTimeoutAction"; + final String checkPendingOperationsActionMethod = "checkPendingOperationsAction"; + + // SETUP + builder.onEntry(State.SETUP) + .perform(new FlowSyncSetupAction(persistenceManager, dashboardLogger)); + builder.transition().from(State.SETUP).to(State.SYNC).on(Event.NEXT); + builder.transition().from(State.SETUP).to(State.COMMIT_ERROR).on(Event.ERROR); + + // SYNC + builder.onEntry(State.SYNC) + .perform(new CreateSyncHandlersAction( + carrier, persistenceManager, resourcesManager, flowPathOperationConfig)); + builder.transition().from(State.SYNC).to(State.SYNC_FAIL).on(Event.SYNC_FAIL); + builder.transition().from(State.SYNC).to(State.COMMIT_SUCCESS).on(Event.GUARD_PASSED); + builder.transition().from(State.SYNC).to(State.CANCEL).on(Event.ERROR); + builder.transition().from(State.SYNC).to(State.CANCEL).on(Event.TIMEOUT) + .callMethod(reportGlobalTimeoutActionMethod); + builder.internalTransition().within(State.SYNC).on(Event.PATH_OPERATION_RESPONSE) + .perform(pathOperationResponseAction); + + // CANCEL + builder.onEntry(State.CANCEL) + .callMethod("enterCancelAction"); + builder.transition().from(State.CANCEL).to(State.COMMIT_ERROR).on(Event.GUARD_PASSED); + builder.internalTransition().within(State.CANCEL).on(Event.PATH_OPERATION_RESPONSE) + .perform(pathOperationResponseAction); + builder.internalTransition().within(State.CANCEL).on(Event.ERROR) + .callMethod(checkPendingOperationsActionMethod); + builder.internalTransition().within(State.CANCEL).on(Event.TIMEOUT) + .callMethod(reportGlobalTimeoutActionMethod); + + // SYNC_FAIL + builder.onEntry(State.SYNC_FAIL) + .callMethod(checkPendingOperationsActionMethod); + builder.transition().from(State.SYNC_FAIL).to(State.COMMIT_ERROR).on(Event.GUARD_PASSED); + builder.transition().from(State.SYNC_FAIL).to(State.CANCEL).on(Event.ERROR); + builder.transition().from(State.SYNC_FAIL).to(State.CANCEL).on(Event.TIMEOUT) + .callMethod(reportGlobalTimeoutActionMethod); + builder.internalTransition().within(State.SYNC_FAIL).on(Event.PATH_OPERATION_RESPONSE) + .perform(pathOperationResponseAction); + + // COMMIT_SUCCESS + builder.onEntry(State.COMMIT_SUCCESS) + .perform(new SuccessCompleteAction(carrier, persistenceManager, dashboardLogger)); + builder.transition().from(State.COMMIT_SUCCESS).to(State.FINISHED).on(Event.NEXT); + builder.transition().from(State.COMMIT_SUCCESS).to(State.COMMIT_ERROR).on(Event.ERROR); + + // COMMIT_ERROR + builder.onEntry(State.COMMIT_ERROR) + .perform(new FailedCompleteAction(carrier, persistenceManager, dashboardLogger)); + builder.transition().from(State.COMMIT_ERROR).to(State.FINISHED_WITH_ERROR).on(Event.NEXT); + + // final + builder.defineFinalState(State.FINISHED); + builder.defineFinalState(State.FINISHED_WITH_ERROR); + } + + public FlowSyncFsm newInstance(@NonNull String flowId, @NonNull CommandContext commandContext) { + FlowSyncFsm instance = builder.newStateMachine(State.SETUP, commandContext, carrier, flowId); + + addExecutionTimeMeter(instance); + addCompleteNotification(instance); + + instance.start(FlowSyncContext.builder().build()); + + return instance; + } + } + + public enum State { + SETUP, + SYNC, SYNC_FAIL, CANCEL, + COMMIT_SUCCESS, COMMIT_ERROR, + FINISHED, FINISHED_WITH_ERROR, + } + + public enum Event { + NEXT, GUARD_PASSED, ERROR, TIMEOUT, SYNC_FAIL, + PATH_OPERATION_RESPONSE + } + + private static void addExecutionTimeMeter(FlowSyncFsm fsm) { + FsmUtil.addExecutionTimeMeter(fsm, () -> successResultAdapter(fsm)); + } + + private static void addCompleteNotification(FlowSyncFsm fsm) { + fsm.addTerminateListener(dummy -> fsm.onComplete()); + } + + private static Boolean successResultAdapter(FlowSyncFsm fsm) { + if (fsm.isTerminated()) { + return fsm.getCurrentState() == State.FINISHED; + } + + return null; + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/CreateSyncHandlersAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/CreateSyncHandlersAction.java new file mode 100644 index 00000000000..eb83db9382f --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/CreateSyncHandlersAction.java @@ -0,0 +1,138 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.sync.actions; + +import org.openkilda.model.Flow; +import org.openkilda.model.FlowPath; +import org.openkilda.model.FlowPathStatus; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.model.SpeakerRequestBuildContext; +import org.openkilda.wfm.topology.flowhs.exception.DuplicateKeyException; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncContext; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.Event; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.State; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathChunk; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationDescriptor; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.service.FlowCommandBuilder; +import org.openkilda.wfm.topology.flowhs.service.FlowCommandBuilderFactory; +import org.openkilda.wfm.topology.flowhs.service.FlowSegmentRequestFactoriesSequence; +import org.openkilda.wfm.topology.flowhs.service.FlowSyncCarrier; + +import lombok.NonNull; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CreateSyncHandlersAction + extends FlowProcessingWithHistorySupportAction { + private final FlowSyncCarrier carrier; + private final FlowCommandBuilderFactory commandBuilderFactory; + private final FlowPathOperationConfig flowPathOperationConfig; + + public CreateSyncHandlersAction( + @NonNull FlowSyncCarrier carrier, @NonNull PersistenceManager persistenceManager, + @NonNull FlowResourcesManager resourcesManager, + @NonNull FlowPathOperationConfig flowPathOperationConfig) { + super(persistenceManager); + + this.carrier = carrier; + this.commandBuilderFactory = new FlowCommandBuilderFactory(resourcesManager); + this.flowPathOperationConfig = flowPathOperationConfig; + } + + @Override + protected void perform(State from, State to, Event event, FlowSyncContext context, FlowSyncFsm stateMachine) { + Flow flow = getFlow(stateMachine.getFlowId()); + FlowCommandBuilder commandBuilder = commandBuilderFactory.getBuilder(flow.getEncapsulationType()); + + proceedPathPair(stateMachine, commandBuilder, flow, flow.getForwardPath(), flow.getReversePath()); + if (flow.getProtectedForwardPathId() != null) { + proceedPathPairSkippingIngressChunk( + stateMachine, commandBuilder, flow, flow.getProtectedForwardPath(), flow.getProtectedReversePath()); + } + } + + private void proceedPathPair( + FlowSyncFsm stateMachine, FlowCommandBuilder commandBuilder, Flow flow, FlowPath path, + FlowPath oppositePath) { + SpeakerRequestBuildContext speakerContext = buildBaseSpeakerContextForInstall( + path.getSrcSwitchId(), path.getDestSwitchId()); + + CommandContext commandContext = stateMachine.getCommandContext(); + Pair notIngressPair = + commandBuilder.buildAllExceptIngressSeverally(commandContext, flow, path, oppositePath); + Pair ingressPair = + commandBuilder.buildIngressOnlySeverally(commandContext, flow, path, oppositePath, speakerContext); + + proceedPath(stateMachine, flow.getFlowId(), path, notIngressPair.getLeft(), ingressPair.getLeft()); + proceedPath(stateMachine, flow.getFlowId(), oppositePath, notIngressPair.getRight(), ingressPair.getRight()); + } + + private void proceedPath( + FlowSyncFsm stateMachine, String flowId, FlowPath path, + FlowSegmentRequestFactoriesSequence notIngressSequence, + FlowSegmentRequestFactoriesSequence ingressSequence) { + List chunks = Arrays.asList( + new FlowPathChunk(PathChunkType.NOT_INGRESS, notIngressSequence), + new FlowPathChunk(PathChunkType.INGRESS, ingressSequence)); + FlowPathRequest request = new FlowPathRequest(flowId, path.getPathId(), chunks, false); + launchPathInstall(stateMachine, path, request); + } + + private void proceedPathPairSkippingIngressChunk( + FlowSyncFsm stateMachine, FlowCommandBuilder commandBuilder, Flow flow, FlowPath path, + FlowPath oppositePath) { + Pair sequences = + commandBuilder.buildAllExceptIngressSeverally( + stateMachine.getCommandContext(), flow, path, oppositePath); + proceedPathSkippingIngressChunk(stateMachine, flow.getFlowId(), path, sequences.getLeft()); + proceedPathSkippingIngressChunk(stateMachine, flow.getFlowId(), oppositePath, sequences.getRight()); + } + + private void proceedPathSkippingIngressChunk( + FlowSyncFsm stateMachine, String flowId, FlowPath path, FlowSegmentRequestFactoriesSequence sequence) { + List chunks = Collections.singletonList( + new FlowPathChunk(PathChunkType.NOT_INGRESS, sequence)); + FlowPathRequest request = new FlowPathRequest(flowId, path.getPathId(), chunks, false); + launchPathInstall(stateMachine, path, request); + } + + private void launchPathInstall( + FlowSyncFsm stateMachine, FlowPath path, FlowPathRequest request) { + FlowPathOperationDescriptor descriptor = new FlowPathOperationDescriptor(request, path.getStatus()); + path.setStatus(FlowPathStatus.IN_PROGRESS); + + try { + carrier.launchFlowPathInstallation(request, flowPathOperationConfig, stateMachine.getCommandContext()); + } catch (DuplicateKeyException e) { + throw new IllegalStateException( + String.format( + "Unable to initiate flow path install operation due to path operations collision: %s", + e.getMessage()), e); + } + + stateMachine.addPendingPathOperation(descriptor); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FailedCompleteAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FailedCompleteAction.java new file mode 100644 index 00000000000..b1c592e4975 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FailedCompleteAction.java @@ -0,0 +1,105 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.sync.actions; + +import static java.lang.String.format; + +import org.openkilda.messaging.error.ErrorData; +import org.openkilda.messaging.error.ErrorMessage; +import org.openkilda.messaging.error.ErrorType; +import org.openkilda.model.Flow; +import org.openkilda.model.FlowStatus; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncContext; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.Event; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.State; +import org.openkilda.wfm.topology.flowhs.service.FlowSyncCarrier; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FailedCompleteAction + extends FlowProcessingWithHistorySupportAction { + private static final String OPERATION_LEVEL_ERROR_MESSAGE = "Could not sync flow"; + + private final FlowSyncCarrier carrier; + private final FlowOperationsDashboardLogger dashboardLogger; + + public FailedCompleteAction( + @NonNull FlowSyncCarrier carrier, @NonNull PersistenceManager persistenceManager, + FlowOperationsDashboardLogger dashboardLogger) { + super(persistenceManager); + + this.carrier = carrier; + this.dashboardLogger = dashboardLogger; + } + + @Override + protected void perform(State from, State to, Event event, FlowSyncContext context, FlowSyncFsm stateMachine) { + if (context.getErrorType() == null) { + reportGenericFailure(stateMachine); + } else { + reportSpecificFailure(context.getErrorType(), context.getErrorDetails(), stateMachine.getCommandContext()); + } + stateMachine.fireNext(context); + } + + private void reportGenericFailure(FlowSyncFsm stateMachine) { + Flow flow = getFlow(stateMachine.getFlowId()); + + final int failCount = stateMachine.getPathOperationFail().size(); + final int successCount = stateMachine.getPathOperationSuccess().size(); + + FlowStatus status = flow.computeFlowStatus(); + if (stateMachine.isDangerousSync()) { + flow.setStatus(FlowStatus.DOWN); + flow.setStatusInfo(String.format( + "%d of %d path operations have failed during DANGEROUS sync attempt", + failCount, failCount + successCount)); + } else if (FlowStatus.UP != status) { + flow.setStatus(status); + flow.setStatusInfo(String.format( + "%d of %d path operations have failed during sync attempt", failCount, failCount + successCount)); + } else { + flow.setStatus(FlowStatus.DEGRADED); + flow.setStatusInfo("Failed to update flow info during sync, some flow fields can contain not actual info"); + } + stateMachine.saveActionToHistory(format("The flow status was set to %s", flow.getStatus())); + log.error("{} - setting flow \"{}\" status to {}", flow.getStatusInfo(), flow.getFlowId(), flow.getStatus()); + + ErrorData error = new ErrorData( + ErrorType.INTERNAL_ERROR, OPERATION_LEVEL_ERROR_MESSAGE, + format("Failed to sync flow %s", flow.getFlowId())); + sendResponse(error, stateMachine.getCommandContext()); + + dashboardLogger.onFailedFlowSync(flow.getFlowId(), failCount, failCount + successCount); + } + + private void reportSpecificFailure(ErrorType errorType, String errorDetails, CommandContext commandContext) { + ErrorData error = new ErrorData(errorType, OPERATION_LEVEL_ERROR_MESSAGE, errorDetails); + sendResponse(error, commandContext); + } + + private void sendResponse(ErrorData payload, CommandContext commandContext) { + carrier.sendNorthboundResponse( + new ErrorMessage(payload, System.currentTimeMillis(), commandContext.getCorrelationId())); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FlowSyncSetupAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FlowSyncSetupAction.java new file mode 100644 index 00000000000..e076529ac72 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/FlowSyncSetupAction.java @@ -0,0 +1,94 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.sync.actions; + +import static java.lang.String.format; + +import org.openkilda.messaging.error.ErrorType; +import org.openkilda.model.Flow; +import org.openkilda.model.FlowStatus; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.share.history.model.FlowEventData; +import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; +import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncContext; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.Event; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.State; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FlowSyncSetupAction + extends FlowProcessingWithHistorySupportAction { + private final FlowOperationsDashboardLogger dashboardLogger; + + public FlowSyncSetupAction(PersistenceManager persistenceManager, FlowOperationsDashboardLogger dashboardLogger) { + super(persistenceManager); + this.dashboardLogger = dashboardLogger; + } + + @Override + protected void perform(State from, State to, Event event, FlowSyncContext context, FlowSyncFsm stateMachine) { + try { + transactionManager.doInTransaction(() -> transaction(stateMachine)); + stateMachine.fireNext(context); + } catch (FlowProcessingException e) { + FlowSyncContext errorContext = FlowSyncContext.builder() + .errorType(e.getErrorType()) + .errorDetails(e.getMessage()) + .build(); + stateMachine.fireError(errorContext); + } + } + + + private void transaction(FlowSyncFsm stateMachine) { + Flow flow = getFlow(stateMachine.getFlowId()); + + dashboardLogger.onFlowSync(stateMachine.getFlowId()); + stateMachine.saveNewEventToHistory( + "Started flow paths sync", FlowEventData.Event.SYNC, FlowEventData.Initiator.NB, + "Performing flow paths sync operation on NB request"); + + ensureNoCollision(flow); + + flow.setStatus(FlowStatus.IN_PROGRESS); + stateMachine.setDangerousSync(applyFlowPostponedChanges(flow)); + } + + private void ensureNoCollision(Flow flow) { + if (flow.getStatus() == FlowStatus.IN_PROGRESS) { + String message = format("Flow %s is in progress now", flow.getFlowId()); + throw new FlowProcessingException(ErrorType.REQUEST_INVALID, message); + } + } + + private boolean applyFlowPostponedChanges(Flow flow) { + if (flow.getTargetPathComputationStrategy() != null) { + log.warn( + "Changing flow \"{}\" path computation strategy from {} to {}, because of this the SYNC operation " + + "become UNSAFE (client traffic during path update can be interrupted, flow can become " + + "corrupted if any path segment will not be installed)", + flow.getFlowId(), flow.getPathComputationStrategy(), flow.getTargetPathComputationStrategy()); + flow.setPathComputationStrategy(flow.getTargetPathComputationStrategy()); + flow.setTargetPathComputationStrategy(null); + return true; + } + return false; + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/PathOperationResponseAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/PathOperationResponseAction.java new file mode 100644 index 00000000000..0cf51be1e60 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/PathOperationResponseAction.java @@ -0,0 +1,75 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.sync.actions; + +import org.openkilda.model.FlowPathStatus; +import org.openkilda.model.PathId; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncContext; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.Event; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.State; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationDescriptor; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PathOperationResponseAction + extends FlowProcessingWithHistorySupportAction { + public PathOperationResponseAction(@NonNull PersistenceManager persistenceManager) { + super(persistenceManager); + } + + @Override + protected void perform(State from, State to, Event event, FlowSyncContext context, FlowSyncFsm stateMachine) { + FlowPathResultCode resultCode = context.getPathResultCode(); + PathId pathId = context.getPathId(); + if (resultCode == FlowPathResultCode.SUCCESS) { + handleSuccess( + stateMachine, stateMachine.addSuccessPathOperation(pathId) + .orElseThrow(() -> newMissingPendingOperationError(pathId, resultCode))); + } else { + FlowPathOperationDescriptor descriptor = stateMachine.addFailedPathOperation(pathId) + .orElseThrow(() -> newMissingPendingOperationError(pathId, resultCode)); + handleFailure(stateMachine, descriptor); + stateMachine.fire(Event.SYNC_FAIL, context); + } + + if (! stateMachine.isPendingPathOperationsExists()) { + stateMachine.fire(Event.GUARD_PASSED, context); + } + } + + private void handleSuccess(FlowSyncFsm stateMachine, FlowPathOperationDescriptor descriptor) { + log.info("Flow path {} have been synced (flowId={})", descriptor.getPathId(), stateMachine.getFlowId()); + flowPathRepository.updateStatus(descriptor.getPathId(), FlowPathStatus.ACTIVE); + } + + private void handleFailure(FlowSyncFsm stateMachine, FlowPathOperationDescriptor descriptor) { + log.error( + "Failed to sync flow path {}, restore it's status to initial value {} (flowId={})", + descriptor.getPathId(), descriptor.getInitialStatus(), stateMachine.getFlowId()); + flowPathRepository.updateStatus(descriptor.getPathId(), descriptor.getInitialStatus()); + } + + private IllegalStateException newMissingPendingOperationError(PathId pathId, FlowPathResultCode resultCode) { + return new IllegalStateException(String.format( + "Got unexpected path operation(sync) result pathId=%s, resultCode=%s", pathId, resultCode)); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/SuccessCompleteAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/SuccessCompleteAction.java new file mode 100644 index 00000000000..1681a9b089f --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/sync/actions/SuccessCompleteAction.java @@ -0,0 +1,79 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.sync.actions; + +import org.openkilda.messaging.info.InfoMessage; +import org.openkilda.messaging.info.flow.FlowRerouteResponse; +import org.openkilda.model.Flow; +import org.openkilda.model.FlowPath; +import org.openkilda.model.FlowStatus; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; +import org.openkilda.wfm.share.mappers.FlowPathMapper; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncContext; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.Event; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.State; +import org.openkilda.wfm.topology.flowhs.service.FlowSyncCarrier; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SuccessCompleteAction + extends FlowProcessingWithHistorySupportAction { + private final FlowSyncCarrier carrier; + private final FlowOperationsDashboardLogger dashboardLogger; + + public SuccessCompleteAction( + FlowSyncCarrier carrier, @NonNull PersistenceManager persistenceManager, + @NonNull FlowOperationsDashboardLogger dashboardLogger) { + super(persistenceManager); + + this.carrier = carrier; + this.dashboardLogger = dashboardLogger; + } + + @Override + protected void perform(State from, State to, Event event, FlowSyncContext context, FlowSyncFsm stateMachine) { + Flow flow = getFlow(stateMachine.getFlowId()); + FlowStatus status = flow.computeFlowStatus(); + flow.setStatus(status); + if (status == FlowStatus.UP) { + flow.setStatusInfo(null); + } else if (status == FlowStatus.DEGRADED) { + log.debug("Keep flow {} into {} status", flow.getFlowId(), status); + } else { + stateMachine.fireError(); + return; + } + + sendResponse(flow.getForwardPath(), stateMachine.getCommandContext()); + + dashboardLogger.onSuccessfulFlowSync(flow.getFlowId()); + + stateMachine.fireNext(context); + } + + private void sendResponse(FlowPath path, CommandContext commandContext) { + // Setting "rerouted" payload field into false, because paths are always kept unchanged now + FlowRerouteResponse payload = new FlowRerouteResponse(FlowPathMapper.INSTANCE.map(path), false); + carrier.sendNorthboundResponse( + new InfoMessage(payload, System.currentTimeMillis(), commandContext.getCorrelationId())); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathChunk.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathChunk.java new file mode 100644 index 00000000000..979b1863ec7 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathChunk.java @@ -0,0 +1,32 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.model.path; + +import org.openkilda.floodlight.api.request.factory.FlowSegmentRequestFactory; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; + +import lombok.NonNull; +import lombok.Value; + +import java.util.List; + +@Value +public class FlowPathChunk { + PathChunkType type; + + @NonNull + List payload; +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationConfig.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationConfig.java new file mode 100644 index 00000000000..dee02dd2973 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationConfig.java @@ -0,0 +1,23 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.model.path; + +import lombok.Value; + +@Value +public class FlowPathOperationConfig { + int speakerCommandRetriesLimit; +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationDescriptor.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationDescriptor.java new file mode 100644 index 00000000000..a35609a2ce4 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathOperationDescriptor.java @@ -0,0 +1,32 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.model.path; + +import org.openkilda.model.FlowPathStatus; +import org.openkilda.model.PathId; + +import lombok.Value; + +@Value +public class FlowPathOperationDescriptor { + FlowPathRequest request; + + FlowPathStatus initialStatus; + + public PathId getPathId() { + return request.getReference().getPathId(); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathReference.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathReference.java new file mode 100644 index 00000000000..da523de9857 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathReference.java @@ -0,0 +1,30 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.model.path; + +import org.openkilda.model.PathId; + +import lombok.NonNull; +import lombok.Value; + +@Value +public class FlowPathReference { + @NonNull + String flowId; + + @NonNull + PathId pathId; +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathRequest.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathRequest.java new file mode 100644 index 00000000000..c1847c2375a --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathRequest.java @@ -0,0 +1,55 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.model.path; + +import org.openkilda.model.PathId; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NonNull; +import lombok.Singular; +import lombok.Value; + +import java.util.List; + +// TODO(surabujin): better name? +@Value +@AllArgsConstructor +public class FlowPathRequest { + @NonNull + FlowPathReference reference; + + @NonNull + List pathChunks; + + boolean canRevertOnError; + + public FlowPathRequest(@NonNull String flowId, @NonNull PathId pathId, @NonNull List pathChunks) { + this(flowId, pathId, pathChunks, true); + } + + @Builder + public FlowPathRequest( + @NonNull String flowId, @NonNull PathId pathId, @Singular @NonNull List pathChunks, + boolean canRevertOnError) { + this(new FlowPathReference(flowId, pathId), pathChunks, canRevertOnError); + } + + public enum PathChunkType { + INGRESS, NOT_INGRESS, ALL_AT_ONCE, + REVERT + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResult.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResult.java new file mode 100644 index 00000000000..66ed62ec20c --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResult.java @@ -0,0 +1,24 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.model.path; + +import lombok.Value; + +@Value +public class FlowPathResult { + FlowPathReference reference; + FlowPathResultCode resultCode; +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResultCode.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResultCode.java new file mode 100644 index 00000000000..8203083dbb8 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/model/path/FlowPathResultCode.java @@ -0,0 +1,20 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.model.path; + +public enum FlowPathResultCode { + SUCCESS, CANCEL, SPEAKER_ERROR +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSwapEndpointsHubService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSwapEndpointsHubService.java index 3cf53a4ba69..43d15c3eec1 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSwapEndpointsHubService.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSwapEndpointsHubService.java @@ -36,7 +36,7 @@ @Slf4j public class FlowSwapEndpointsHubService extends FlowProcessingService, + FlowSwapEndpointsContext, FlowSwapEndpointsHubCarrier, FsmRegister, FlowProcessingEventListener> { private final FlowSwapEndpointsFsm.Factory fsmFactory; diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncCarrier.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncCarrier.java new file mode 100644 index 00000000000..cf54af3ea7d --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncCarrier.java @@ -0,0 +1,33 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service; + +import org.openkilda.model.PathId; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.topology.flowhs.exception.DuplicateKeyException; +import org.openkilda.wfm.topology.flowhs.exception.UnknownKeyException; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; + +import lombok.NonNull; + +public interface FlowSyncCarrier extends FlowGenericCarrier { + void launchFlowPathInstallation( + @NonNull FlowPathRequest request, @NonNull FlowPathOperationConfig config, + @NonNull CommandContext commandContext) throws DuplicateKeyException; + + void cancelFlowPathOperation(PathId pathId) throws UnknownKeyException; +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncService.java new file mode 100644 index 00000000000..e6baee0deec --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncService.java @@ -0,0 +1,104 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service; + +import org.openkilda.messaging.command.flow.FlowSyncRequest; +import org.openkilda.messaging.error.ErrorData; +import org.openkilda.messaging.error.ErrorMessage; +import org.openkilda.messaging.error.ErrorType; +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncContext; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm; +import org.openkilda.wfm.topology.flowhs.fsm.sync.FlowSyncFsm.Event; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathReference; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; +import org.openkilda.wfm.topology.flowhs.service.common.FlowProcessingFsmRegister; +import org.openkilda.wfm.topology.flowhs.service.common.FlowProcessingService; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +import java.util.Optional; + +@Slf4j +public class FlowSyncService extends FlowProcessingService, FlowProcessingEventListener> { + private final FlowSyncFsm.Factory handlerFactory; + + public FlowSyncService( + @NonNull FlowSyncCarrier carrier, @NonNull PersistenceManager persistenceManager, + @NonNull FlowResourcesManager flowResourcesManager, + @NonNull FlowPathOperationConfig flowPathOperationConfig) { + super(new FlowProcessingFsmRegister<>(), FlowSyncFsm.EXECUTOR, carrier, persistenceManager); + handlerFactory = new FlowSyncFsm.Factory( + carrier, persistenceManager, flowResourcesManager, flowPathOperationConfig); + } + + /** + * Handle flow sync request. + */ + public void handleRequest(String requestKey, FlowSyncRequest request, CommandContext commandContext) { + String flowId = request.getFlowId(); + log.debug("Handling flow reroute request with key {} and flow ID: {}", requestKey, flowId); + + // Because of field grouping specific flowId goes into specific bolt instance, so we can do such checks + if (fsmRegister.hasRegisteredFsmWithFlowId(flowId)) { + ErrorData payload = new ErrorData( + ErrorType.BUSY, "Overlapping flow sync requests", + String.format("Flow %s are doing \"sync\" already", flowId)); + carrier.sendNorthboundResponse(new ErrorMessage( + payload, commandContext.getCreateTime(), commandContext.getCorrelationId())); + return; + } + + FlowSyncFsm handler = handlerFactory.newInstance(request.getFlowId(), commandContext); + fsmRegister.registerFsm(requestKey, handler); + handler.getResultFuture() + .thenAccept(dummy -> onComplete(requestKey)); + } + + /** + * Handle global operation timeout. + */ + public void handleTimeout(String requestKey) { + fsmRegister.getFsmByKey(requestKey) + .ifPresent(FlowSyncFsm::handleTimeout); + } + + /** + * Handle flow path sync(install) operation results. + */ + public void handlePathSyncResponse(FlowPathReference reference, FlowPathResultCode result) { + Optional handler = fsmRegister.getFsmByFlowId(reference.getFlowId()); + if (handler.isPresent()) { + handler.get().handlePathOperationResult(reference.getPathId(), result); + } else { + log.error("Got path sync result for {} but there is no relative sync handler", reference); + } + } + + private void onComplete(String requestKey) { + fsmRegister.unregisterFsm(requestKey); + carrier.cancelTimeoutCallback(requestKey); + + if (!isActive() && !fsmRegister.hasAnyRegisteredFsm()) { + carrier.sendInactive(); + } + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHistoryCarrier.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHistoryCarrier.java new file mode 100644 index 00000000000..af35ab22b6b --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHistoryCarrier.java @@ -0,0 +1,33 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service.common; + +public interface FlowHistoryCarrier { + /** + * Add a history record on the action. + */ + void saveActionToHistory(String action, String description); + + /** + * Add a history record on the error. + */ + void saveErrorToHistory(String action, String errorMessage); + + /** + * Add a history record on the error. + */ + void saveErrorToHistory(String errorMessage); +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHsService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHsService.java new file mode 100644 index 00000000000..c25ff479f69 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowHsService.java @@ -0,0 +1,41 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service.common; + +import lombok.AccessLevel; +import lombok.Getter; + +public abstract class FlowHsService { + @Getter(AccessLevel.PROTECTED) + private boolean active; + + /** + * Handles deactivate command. + */ + public boolean deactivate() { + boolean isChanged = active; + active = false; + + return isChanged; + } + + /** + * Handles activate command. + */ + public void activate() { + active = true; + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingFsmRegister.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingFsmRegister.java index 5ee160a2a65..c6baf170cac 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingFsmRegister.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingFsmRegister.java @@ -25,7 +25,7 @@ import java.util.Optional; @Slf4j -public class FlowProcessingFsmRegister> extends FsmRegister { +public class FlowProcessingFsmRegister> extends FsmRegister { private final Map keyByFlowId = new HashMap<>(); @Override diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingService.java index 1e5fd203654..d91e4b79d26 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingService.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FlowProcessingService.java @@ -33,7 +33,7 @@ @Slf4j public abstract class FlowProcessingService, E, C, - R extends NorthboundResponseCarrier & LifecycleEventCarrier, F extends FsmRegister, + R extends NorthboundResponseCarrier & LifecycleEventCarrier, F extends FsmRegister, L extends ProcessingEventListener> extends FsmBasedProcessingService { protected final R carrier; protected final FlowRepository flowRepository; diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmBasedProcessingService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmBasedProcessingService.java index cd8b3e870cf..0db7837c154 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmBasedProcessingService.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmBasedProcessingService.java @@ -17,25 +17,18 @@ import org.openkilda.wfm.share.utils.FsmExecutor; -import lombok.AccessLevel; -import lombok.Getter; import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine; import java.util.HashSet; import java.util.Set; -@Slf4j public abstract class FsmBasedProcessingService, E, C, - F extends FsmRegister, L extends ProcessingEventListener> { + F extends FsmRegister, L extends ProcessingEventListener> extends FlowHsService { protected final F fsmRegister; protected final FsmExecutor fsmExecutor; protected final Set eventListeners = new HashSet<>(); - @Getter(AccessLevel.PROTECTED) - private boolean active; - protected FsmBasedProcessingService(@NonNull F fsmRegister, @NonNull FsmExecutor fsmExecutor) { this.fsmRegister = fsmRegister; @@ -46,18 +39,9 @@ public void addEventListener(@NonNull L eventListener) { eventListeners.add(eventListener); } - /** - * Handles deactivate command. - */ + @Override public boolean deactivate() { - active = false; + super.deactivate(); return !fsmRegister.hasAnyRegisteredFsm(); } - - /** - * Handles activate command. - */ - public void activate() { - active = true; - } } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmRegister.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmRegister.java index 8e0f432cf60..c819d907d19 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmRegister.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/common/FsmRegister.java @@ -23,14 +23,14 @@ import java.util.Optional; @Slf4j -public class FsmRegister> { - private final Map fsmByKey = new HashMap<>(); +public class FsmRegister> { + private final Map fsmByKey = new HashMap<>(); - public void registerFsm(String key, T fsm) { + public void registerFsm(K key, T fsm) { fsmByKey.put(key, fsm); } - public boolean hasRegisteredFsmWithKey(String key) { + public boolean hasRegisteredFsmWithKey(K key) { return fsmByKey.containsKey(key); } @@ -38,11 +38,11 @@ public boolean hasAnyRegisteredFsm() { return !fsmByKey.isEmpty(); } - public Optional getFsmByKey(String key) { + public Optional getFsmByKey(K key) { return Optional.ofNullable(fsmByKey.get(key)); } - public T unregisterFsm(String key) { + public T unregisterFsm(K key) { return fsmByKey.remove(key); } } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathCarrier.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathCarrier.java new file mode 100644 index 00000000000..75281edbd5a --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathCarrier.java @@ -0,0 +1,23 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service.path; + +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResult; +import org.openkilda.wfm.topology.flowhs.service.FlowGenericCarrier; + +public interface FlowPathCarrier extends FlowGenericCarrier { + void processFlowPathOperationResults(FlowPathResult result); +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathService.java new file mode 100644 index 00000000000..83aa52b01d6 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathService.java @@ -0,0 +1,130 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service.path; + +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.topology.flowhs.exception.DuplicateKeyException; +import org.openkilda.wfm.topology.flowhs.exception.UnknownKeyException; +import org.openkilda.wfm.topology.flowhs.fsm.path.FlowPathInstallFsm; +import org.openkilda.wfm.topology.flowhs.fsm.path.FlowPathOperation; +import org.openkilda.wfm.topology.flowhs.fsm.path.FlowPathRemoveFsm; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathReference; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResult; +import org.openkilda.wfm.topology.flowhs.service.common.FlowHsService; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; + +@Slf4j +public class FlowPathService extends FlowHsService { + private final Map registry = new HashMap<>(); + + private final FlowPathCarrier carrier; + private final FlowPathInstallFsm.Factory installOperationFactory; + private final FlowPathRemoveFsm.Factory removeOperationFactory; + + public FlowPathService(@NonNull FlowPathCarrier carrier) { + this.carrier = carrier; + installOperationFactory = new FlowPathInstallFsm.Factory(carrier); + removeOperationFactory = new FlowPathRemoveFsm.Factory(carrier); + } + + /** + * Launch flow path install operation. + */ + public void installPath( + @NonNull FlowPathRequest request, @NonNull String requestKey, @NonNull FlowPathOperationConfig config, + @NonNull CommandContext commandContext) + throws DuplicateKeyException { + handleRequest( + "install", request.getReference(), requestKey, + () -> installOperationFactory.newInstance(config, request, commandContext)); + } + + /** + * Launch flow path remove operation. + */ + public void removePath( + @NonNull FlowPathRequest request, @NonNull String requestKey, @NonNull FlowPathOperationConfig config, + @NonNull CommandContext commandContext) + throws DuplicateKeyException { + handleRequest( + "remove", request.getReference(), requestKey, + () -> removeOperationFactory.newInstance(config, request, commandContext)); + } + + /** + * Cancel possible running path operation. + */ + public void cancelOperation(@NonNull String requestKey) throws UnknownKeyException { + handleEvent(requestKey, FlowPathOperation::handleCancel); + } + + public void handleSpeakerResponse(@NonNull String requestKey, @NonNull SpeakerFlowSegmentResponse response) + throws UnknownKeyException { + handleEvent(requestKey, handler -> handler.handleSpeakerResponse(response)); + } + + private void handleRequest( + String operationName, FlowPathReference reference, String requestKey, + Supplier handlerSupplier) throws DuplicateKeyException { + log.debug("Handling {} {} request (key={})", reference, operationName, requestKey); + + ensureNoOperationCollisions(requestKey, operationName); + FlowPathOperation handler = handlerSupplier.get(); + registry.put(requestKey, handler); + handler.getResultFuture() + .thenAccept(result -> onComplete(operationName, requestKey, handler, result)); + } + + private void handleEvent(String requestKey, Consumer action) throws UnknownKeyException { + FlowPathOperation handler = registry.get(requestKey); + if (handler == null) { + throw new UnknownKeyException(requestKey); + } + action.accept(handler); + } + + private void onComplete( + String operationName, String requestKey, FlowPathOperation operation, FlowPathResult result) { + log.debug( + "Flow path {} operation with reference {} completed with result {}", + operation.getPathReference(), operationName, operation.getResultCode()); + + registry.remove(requestKey); + carrier.processFlowPathOperationResults(result); + + if (registry.isEmpty()) { + carrier.sendInactive(); + } + } + + private void ensureNoOperationCollisions(String requestKey, String operationName) throws DuplicateKeyException { + if (registry.containsKey(requestKey)) { + throw new DuplicateKeyException( + requestKey, String.format( + "Flow path %s requests collision path reference %s", operationName, requestKey)); + } + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncServiceTest.java b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncServiceTest.java new file mode 100644 index 00000000000..6e8c330d80e --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowSyncServiceTest.java @@ -0,0 +1,236 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; + +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.messaging.command.flow.FlowSyncRequest; +import org.openkilda.model.Flow; +import org.openkilda.model.FlowPathStatus; +import org.openkilda.model.FlowStatus; +import org.openkilda.model.PathId; +import org.openkilda.persistence.repositories.FlowPathRepository; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathReference; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; + +import com.google.common.collect.Sets; +import lombok.Value; +import org.apache.commons.lang3.function.FailableConsumer; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +@RunWith(MockitoJUnitRunner.class) +public class FlowSyncServiceTest extends AbstractFlowTest { + private static final int SPEAKER_RETRY_LIMIT = 3; + private static final FlowPathOperationConfig PATH_OPERATION_CONFIG = new FlowPathOperationConfig( + SPEAKER_RETRY_LIMIT); + + @Mock + private FlowSyncCarrier carrier; + + private final Queue pathRequests = new ArrayDeque<>(); + + @Before + public void setUp() throws Exception { + doAnswer(invocation -> { + CarrierLaunchPathOperation pathOperation = new CarrierLaunchPathOperation( + invocation.getArgument(0), invocation.getArgument(1), invocation.getArgument(2)); + pathRequests.offer(pathOperation); + return null; + }).when(carrier).launchFlowPathInstallation(any(), any(), any()); + + setupFlowRepositorySpy(); + setupFlowPathRepositorySpy(); + } + + @Test + public void testGenericSync() throws Exception { + Flow origin = makeFlow(); + FlowPathRepository repository = persistenceManager.getRepositoryFactory().createFlowPathRepository(); + repository.updateStatus(origin.getForwardPathId(), FlowPathStatus.INACTIVE); + + FlowSyncRequest request = new FlowSyncRequest(origin.getFlowId()); + FlowSyncService service = newService(); + + service.handleRequest("request-key", request, new CommandContext("test-correlation-id")); + + List unexpected = new ArrayList<>(); + Set expected = Sets.newHashSet(origin.getForwardPathId(), origin.getReversePathId()); + proceedPathRequests(entry -> { + FlowPathReference reference = entry.getRequest().getReference(); + if (expected.remove(reference.getPathId())) { + service.handlePathSyncResponse(reference, FlowPathResultCode.SUCCESS); + } else { + unexpected.add(entry); + } + }); + + Assert.assertTrue(expected.isEmpty()); + Assert.assertTrue(unexpected.isEmpty()); + + Flow flow = verifyFlowStatus(origin.getFlowId(), FlowStatus.UP); + verifyFlowPathStatus(flow.getForwardPath(), FlowPathStatus.ACTIVE, "forward"); + verifyFlowPathStatus(flow.getReversePath(), FlowPathStatus.ACTIVE, "reversed"); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testProtectedSync() throws Exception { + Flow origin = dummyFactory.makeFlowWithProtectedPath( + flowSource, flowDestination, + Collections.singletonList(islSourceDest), + Arrays.asList(islSourceTransit, islTransitDest)); + FlowPathRepository repository = persistenceManager.getRepositoryFactory().createFlowPathRepository(); + repository.updateStatus(origin.getForwardPathId(), FlowPathStatus.INACTIVE); + repository.updateStatus(origin.getProtectedForwardPathId(), FlowPathStatus.INACTIVE); + + FlowSyncRequest request = new FlowSyncRequest(origin.getFlowId()); + FlowSyncService service = newService(); + + service.handleRequest("request-key", request, new CommandContext("test-correlation-id")); + + List unexpected = new ArrayList<>(); + Set expected = Sets.newHashSet(origin.getForwardPathId(), origin.getReversePathId()); + Set expectedProtected = Sets.newHashSet( + origin.getProtectedForwardPathId(), origin.getProtectedReversePathId()); + proceedPathRequests(entry -> { + FlowPathRequest pathRequest = entry.getRequest(); + FlowPathReference reference = pathRequest.getReference(); + if (expected.remove(reference.getPathId())) { + Assert.assertEquals(2, pathRequest.getPathChunks().size()); + service.handlePathSyncResponse(reference, FlowPathResultCode.SUCCESS); + } else if (expectedProtected.remove(reference.getPathId())) { + Assert.assertEquals(1, pathRequest.getPathChunks().size()); + service.handlePathSyncResponse(reference, FlowPathResultCode.SUCCESS); + } else { + unexpected.add(entry); + } + }); + + Assert.assertTrue(expected.isEmpty()); + Assert.assertTrue(expectedProtected.isEmpty()); + Assert.assertTrue(unexpected.isEmpty()); + + Flow flow = verifyFlowStatus(origin.getFlowId(), FlowStatus.UP); + verifyFlowPathStatus(flow.getForwardPath(), FlowPathStatus.ACTIVE, "forward"); + verifyFlowPathStatus(flow.getReversePath(), FlowPathStatus.ACTIVE, "reversed"); + verifyFlowPathStatus(flow.getProtectedForwardPath(), FlowPathStatus.ACTIVE, "forward-protected"); + verifyFlowPathStatus(flow.getProtectedReversePath(), FlowPathStatus.ACTIVE, "reversed-protected"); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testPathInstallFailure() throws Exception { + Flow origin = makeFlow(); + FlowSyncRequest request = new FlowSyncRequest(origin.getFlowId()); + FlowSyncService service = newService(); + + service.handleRequest("request-key", request, new CommandContext("test-correlation-id")); + + List unexpected = new ArrayList<>(); + proceedPathRequests(entry -> { + FlowPathReference reference = entry.getRequest().getReference(); + if (origin.getReversePathId().equals(reference.getPathId())) { + service.handlePathSyncResponse(reference, FlowPathResultCode.SPEAKER_ERROR); + } else if (origin.getForwardPathId().equals(reference.getPathId())) { + service.handlePathSyncResponse(reference, FlowPathResultCode.SUCCESS); + } else { + unexpected.add(entry); + } + }); + + Assert.assertTrue(unexpected.isEmpty()); + + // All flow's path are in ACTIVE state (same as they were before sync), but due to error during sync + // final flow state will be DEGRADED (so system will try to fix later). + Flow flow = verifyFlowStatus(origin.getFlowId(), FlowStatus.DEGRADED); + verifyFlowPathStatus(flow.getForwardPath(), FlowPathStatus.ACTIVE, "forward"); + verifyFlowPathStatus(flow.getReversePath(), FlowPathStatus.ACTIVE, "reversed"); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testGlobalTimeout() throws Exception { + Flow origin = makeFlow(); + FlowPathRepository repository = persistenceManager.getRepositoryFactory().createFlowPathRepository(); + repository.updateStatus(origin.getForwardPathId(), FlowPathStatus.INACTIVE); + + FlowSyncRequest request = new FlowSyncRequest(origin.getFlowId()); + FlowSyncService service = newService(); + + String requestKey = "request-key"; + service.handleRequest(requestKey, request, new CommandContext("test-correlation-id")); + service.handleTimeout(requestKey); + + verify(carrier).cancelFlowPathOperation(eq(origin.getForwardPathId())); + verify(carrier).cancelFlowPathOperation(eq(origin.getReversePathId())); + + proceedPathRequests(entry -> { + FlowPathReference reference = entry.getRequest().getReference(); + service.handlePathSyncResponse(reference, FlowPathResultCode.CANCEL); + }); + + Flow flow = verifyFlowStatus(origin.getFlowId(), FlowStatus.DOWN); + verifyFlowPathStatus(flow.getForwardPath(), FlowPathStatus.INACTIVE, "forward"); + verifyFlowPathStatus(flow.getReversePath(), FlowPathStatus.ACTIVE, "reversed"); + + Assert.assertTrue(service.deactivate()); + } + + // utility/service + + private void proceedPathRequests(FailableConsumer handler) throws Exception { + for (CarrierLaunchPathOperation entry = pathRequests.poll(); entry != null; entry = pathRequests.poll()) { + handler.accept(entry); + } + } + + private FlowSyncService newService() { + FlowSyncService service = new FlowSyncService( + carrier, persistenceManager, flowResourcesManager, PATH_OPERATION_CONFIG); + service.activate(); + return service; + } + + @Value + private static class CarrierLaunchPathOperation { + FlowPathRequest request; + FlowPathOperationConfig config; + CommandContext commandContext; + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathServiceTest.java b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathServiceTest.java new file mode 100644 index 00000000000..4d35820ea3f --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/path/FlowPathServiceTest.java @@ -0,0 +1,417 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.flowhs.service.path; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; + +import org.openkilda.floodlight.api.request.EgressFlowSegmentInstallRequest; +import org.openkilda.floodlight.api.request.EgressFlowSegmentRemoveRequest; +import org.openkilda.floodlight.api.request.EgressFlowSegmentVerifyRequest; +import org.openkilda.floodlight.api.request.FlowSegmentRequest; +import org.openkilda.floodlight.api.request.IngressFlowSegmentInstallRequest; +import org.openkilda.floodlight.api.request.IngressFlowSegmentRemoveRequest; +import org.openkilda.floodlight.api.request.IngressFlowSegmentVerifyRequest; +import org.openkilda.floodlight.api.request.SpeakerRequest; +import org.openkilda.floodlight.api.request.TransitFlowSegmentInstallRequest; +import org.openkilda.floodlight.api.request.TransitFlowSegmentRemoveRequest; +import org.openkilda.floodlight.api.request.TransitFlowSegmentVerifyRequest; +import org.openkilda.floodlight.api.request.factory.EgressFlowSegmentRequestFactory; +import org.openkilda.floodlight.api.request.factory.IngressFlowSegmentRequestFactory; +import org.openkilda.floodlight.api.request.factory.TransitFlowSegmentRequestFactory; +import org.openkilda.floodlight.api.response.SpeakerFlowSegmentResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse; +import org.openkilda.floodlight.flow.response.FlowErrorResponse.ErrorCode; +import org.openkilda.model.FlowEndpoint; +import org.openkilda.model.FlowPathDirection; +import org.openkilda.model.PathId; +import org.openkilda.model.SwitchId; +import org.openkilda.model.cookie.Cookie; +import org.openkilda.model.cookie.FlowSegmentCookie; +import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.topology.flowhs.exception.UnknownKeyException; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathChunk; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathOperationConfig; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathReference; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathRequest.PathChunkType; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResult; +import org.openkilda.wfm.topology.flowhs.model.path.FlowPathResultCode; +import org.openkilda.wfm.topology.utils.FlowSegmentRequestMetaFactory; + +import com.google.common.base.Objects; +import lombok.Value; +import org.apache.commons.lang3.function.FailableConsumer; +import org.apache.storm.shade.com.google.common.collect.Lists; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; + +@RunWith(MockitoJUnitRunner.class) +public class FlowPathServiceTest { + private final FlowPathOperationConfig config = new FlowPathOperationConfig(3); + + private FlowSegmentRequestMetaFactory flowSegmentRequestMetaFactory; + + private FlowEndpoint ingressEndpoint; + private FlowEndpoint egressEndpoint; + private IngressFlowSegmentRequestFactory ingressSegment; + private TransitFlowSegmentRequestFactory transitSegment; + private EgressFlowSegmentRequestFactory egressSegment; + + @Mock + private FlowPathCarrier carrier; + + private final Queue speakerRequests = new ArrayDeque<>(); + + @Before + public void setUp() throws Exception { + flowSegmentRequestMetaFactory = newFlowSegmentRequestMetaFactory(); + + ingressEndpoint = new FlowEndpoint(new SwitchId(1), 10, 101); + egressEndpoint = new FlowEndpoint(new SwitchId(3), 11, 102); + + ingressSegment = flowSegmentRequestMetaFactory.produceIngressSegmentFactory( + 1000L, ingressEndpoint, 1, egressEndpoint.getSwitchId()); + transitSegment = flowSegmentRequestMetaFactory.produceTransitSegmentFactory(new SwitchId(2), 2, 3); + egressSegment = flowSegmentRequestMetaFactory.produceEgressSegmentFactory(egressEndpoint, 4, ingressEndpoint); + + doAnswer(invocation -> { + SpeakerRequest request = invocation.getArgument(0); + speakerRequests.offer(request); + return request; + }).when(carrier).sendSpeakerRequest(any(SpeakerRequest.class)); + } + + // install + + @Test + public void testInstall() throws Exception { + FlowPathService service = newService(); + final String requestKey = "test-request-key"; + FlowPathRequest pathRequest = newTwoChunkFlowPathRequest(); + service.installPath( + pathRequest, requestKey, config, new CommandContext("test-correlation-id")); + + handleSpeakerRequestAndProvideSuccessResponses(service, requestKey, + // not ingress chunk + new SpeakerFlowSegmentReference(TransitFlowSegmentInstallRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentInstallRequest.class, egressSegment.getSwitchId()), + new SpeakerFlowSegmentReference(TransitFlowSegmentVerifyRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentVerifyRequest.class, egressSegment.getSwitchId()), + // ingress chunk + new SpeakerFlowSegmentReference(IngressFlowSegmentInstallRequest.class, ingressSegment.getSwitchId()), + new SpeakerFlowSegmentReference(IngressFlowSegmentVerifyRequest.class, ingressSegment.getSwitchId())); + + verifyRequestIsOver(pathRequest.getReference(), FlowPathResultCode.SUCCESS); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testInstallSingleChunk() throws Exception { + FlowPathRequest pathRequest = FlowPathRequest.builder() + .flowId(flowSegmentRequestMetaFactory.getFlowId()) + .pathId(new PathId("test-path-id")) + .canRevertOnError(true) + .pathChunk(new FlowPathChunk(PathChunkType.NOT_INGRESS, Arrays.asList(transitSegment, egressSegment))) + .build(); + + FlowPathService service = newService(); + final String requestKey = "test-request-key"; + service.installPath(pathRequest, requestKey, config, new CommandContext("test-correlation-id")); + + handleSpeakerRequestAndProvideSuccessResponses(service, requestKey, + // not ingress chunk + new SpeakerFlowSegmentReference(TransitFlowSegmentInstallRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentInstallRequest.class, egressSegment.getSwitchId()), + new SpeakerFlowSegmentReference(TransitFlowSegmentVerifyRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentVerifyRequest.class, egressSegment.getSwitchId())); + + verifyRequestIsOver(pathRequest.getReference(), FlowPathResultCode.SUCCESS); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testInstallFailsFirstChunk() throws Exception { + FlowPathService service = newService(); + final String requestKey = "test-request-key"; + FlowPathRequest pathRequest = newTwoChunkFlowPathRequest(); + service.installPath( + pathRequest, requestKey, config, new CommandContext("test-correlation-id")); + + SpeakerFlowSegmentReference installTransitSegmentReference = new SpeakerFlowSegmentReference( + TransitFlowSegmentInstallRequest.class, transitSegment.getSwitchId()); + handleSpeakerRequests( + // not ingress + request -> provideFlowSegmentSuccessResultExceptSpecific( + service, installTransitSegmentReference, request, requestKey), + installTransitSegmentReference, // attempt #1 + new SpeakerFlowSegmentReference(EgressFlowSegmentInstallRequest.class, egressSegment.getSwitchId()), + installTransitSegmentReference, // attempt #2 + installTransitSegmentReference, // attempt #3 + // revert + new SpeakerFlowSegmentReference(TransitFlowSegmentRemoveRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentRemoveRequest.class, egressSegment.getSwitchId())); + + verifyRequestIsOver(pathRequest.getReference(), FlowPathResultCode.SPEAKER_ERROR); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testInstallFailsSecondChunk() throws Exception { + FlowPathService service = newService(); + final String requestKey = "test-request-key"; + FlowPathRequest pathRequest = newTwoChunkFlowPathRequest(); + service.installPath( + pathRequest, requestKey, config, new CommandContext("test-correlation-id")); + + SpeakerFlowSegmentReference installIngressSegmentReference = new SpeakerFlowSegmentReference( + IngressFlowSegmentInstallRequest.class, ingressSegment.getSwitchId()); + handleSpeakerRequests( + request -> provideFlowSegmentSuccessResultExceptSpecific( + service, installIngressSegmentReference, request, requestKey), + // not ingress chunk + new SpeakerFlowSegmentReference(TransitFlowSegmentInstallRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentInstallRequest.class, egressSegment.getSwitchId()), + new SpeakerFlowSegmentReference(TransitFlowSegmentVerifyRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentVerifyRequest.class, egressSegment.getSwitchId()), + + // ingress chunk + installIngressSegmentReference, // attempt #1 + installIngressSegmentReference, // attempt #2 + installIngressSegmentReference, // attempt #3 + + // revert + new SpeakerFlowSegmentReference(IngressFlowSegmentRemoveRequest.class, ingressSegment.getSwitchId()), + new SpeakerFlowSegmentReference(TransitFlowSegmentRemoveRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentRemoveRequest.class, egressSegment.getSwitchId())); + + verifyRequestIsOver(pathRequest.getReference(), FlowPathResultCode.SPEAKER_ERROR); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testInstallFailsVerifyFirstChunk() throws Exception { + FlowPathService service = newService(); + final String requestKey = "test-request-key"; + FlowPathRequest pathRequest = newTwoChunkFlowPathRequest(); + service.installPath( + pathRequest, requestKey, config, new CommandContext("test-correlation-id")); + + SpeakerFlowSegmentReference verifyTransitSegmentReference = new SpeakerFlowSegmentReference( + TransitFlowSegmentVerifyRequest.class, transitSegment.getSwitchId()); + handleSpeakerRequests( + // not ingress + request -> provideFlowSegmentSuccessResultExceptSpecific( + service, verifyTransitSegmentReference, request, requestKey), + new SpeakerFlowSegmentReference(TransitFlowSegmentInstallRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentInstallRequest.class, egressSegment.getSwitchId()), + verifyTransitSegmentReference, // attempt #1 + new SpeakerFlowSegmentReference(EgressFlowSegmentVerifyRequest.class, egressSegment.getSwitchId()), + verifyTransitSegmentReference, // attempt #2 + verifyTransitSegmentReference, // attempt #3 + // revert + new SpeakerFlowSegmentReference(TransitFlowSegmentRemoveRequest.class, transitSegment.getSwitchId()), + new SpeakerFlowSegmentReference(EgressFlowSegmentRemoveRequest.class, egressSegment.getSwitchId())); + + verifyRequestIsOver(pathRequest.getReference(), FlowPathResultCode.SPEAKER_ERROR); + + Assert.assertTrue(service.deactivate()); + } + + @Test + public void testInstallFailsWithoutRevert() throws Exception { + FlowPathService service = newService(); + final String requestKey = "test-request-key"; + FlowPathRequest pathRequest = FlowPathRequest.builder() + .flowId(flowSegmentRequestMetaFactory.getFlowId()) + .pathId(new PathId("test-path-id")) + .canRevertOnError(false) + .pathChunk(new FlowPathChunk(PathChunkType.NOT_INGRESS, Arrays.asList(transitSegment, egressSegment))) + .build(); + service.installPath( + pathRequest, requestKey, config, new CommandContext("test-correlation-id")); + + SpeakerFlowSegmentReference installTransitSegmentReference = new SpeakerFlowSegmentReference( + TransitFlowSegmentInstallRequest.class, transitSegment.getSwitchId()); + handleSpeakerRequests( + request -> provideFlowSegmentSuccessResultExceptSpecific( + service, installTransitSegmentReference, request, requestKey), + installTransitSegmentReference, // attempt #1 + installTransitSegmentReference, // attempt #2 + installTransitSegmentReference, // attempt #3 + new SpeakerFlowSegmentReference(EgressFlowSegmentInstallRequest.class, egressSegment.getSwitchId())); + + verifyRequestIsOver(pathRequest.getReference(), FlowPathResultCode.SPEAKER_ERROR); + + Assert.assertTrue(service.deactivate()); + } + + // remove + // TODO + + // utility/service + + private void verifyRequestIsOver(FlowPathReference reference, FlowPathResultCode resultCode) { + Assert.assertTrue(speakerRequests.isEmpty()); + + FlowPathResult result = new FlowPathResult(reference, resultCode); + verify(carrier).processFlowPathOperationResults(eq(result)); + } + + private void handleSpeakerRequestAndProvideSuccessResponses( + FlowPathService service, String requestKey, SpeakerFlowSegmentReference... expectedArray) throws Exception { + handleSpeakerRequests( + request -> service.handleSpeakerResponse( + requestKey, buildSuccessfulSpeakerResponse(request)), expectedArray); + } + + private void provideFlowSegmentSuccessResultExceptSpecific( + FlowPathService service, SpeakerFlowSegmentReference forceFailFor, SpeakerRequest request, + String requestKey) throws UnknownKeyException { + if (forceFailFor.isMatch(request)) { + service.handleSpeakerResponse(requestKey, buildFailedSpeakerResponse(request, ErrorCode.UNKNOWN)); + } else { + service.handleSpeakerResponse(requestKey, buildSuccessfulSpeakerResponse(request)); + } + } + + private void handleSpeakerRequests( + FailableConsumer handler, SpeakerFlowSegmentReference... expectedArray) + throws Exception { + List unexpected = new ArrayList<>(); + List expected = Lists.newArrayList(expectedArray); + proceedSpeakerRequests(request -> { + SpeakerFlowSegmentReference match = null; + for (Iterator iterator = expected.iterator(); iterator.hasNext(); ) { + SpeakerFlowSegmentReference reference = iterator.next(); + if (reference.isMatch(request)) { + iterator.remove(); + match = reference; + break; + } + } + + if (match != null) { + handler.accept(request); + } else { + unexpected.add(request); + } + }); + + Assert.assertTrue(expected.isEmpty()); + Assert.assertTrue(unexpected.isEmpty()); + } + + private void proceedSpeakerRequests(FailableConsumer handler) throws Exception { + for (SpeakerRequest entry = speakerRequests.poll(); entry != null; entry = speakerRequests.poll()) { + handler.accept(entry); + } + } + + private SpeakerFlowSegmentResponse buildSuccessfulSpeakerResponse(SpeakerRequest request) { + if (request instanceof FlowSegmentRequest) { + return buildSuccessfulSpeakerResponse((FlowSegmentRequest) request); + } else { + throw new IllegalArgumentException(String.format( + "Expect %s as argument, but got %s", + FlowSegmentRequest.class.getName(), request.getClass().getName())); + } + } + + private SpeakerFlowSegmentResponse buildSuccessfulSpeakerResponse(FlowSegmentRequest request) { + return SpeakerFlowSegmentResponse.builder() + .messageContext(request.getMessageContext()) + .commandId(request.getCommandId()) + .metadata(request.getMetadata()) + .switchId(request.getSwitchId()) + .success(true) + .build(); + } + + private FlowErrorResponse buildFailedSpeakerResponse(SpeakerRequest request, ErrorCode errorCode) { + if (request instanceof FlowSegmentRequest) { + return buildFailedSpeakerResponse((FlowSegmentRequest) request, errorCode); + } else { + throw new IllegalArgumentException(String.format( + "Expect %s as argument, but got %s", + FlowSegmentRequest.class.getName(), request.getClass().getName())); + } + } + + private FlowErrorResponse buildFailedSpeakerResponse( + FlowSegmentRequest request, ErrorCode errorCode) { + return FlowErrorResponse.errorBuilder() + .messageContext(request.getMessageContext()) + .commandId(request.getCommandId()) + .metadata(request.getMetadata()) + .switchId(request.getSwitchId()) + .description("test-forced-error-response") + .errorCode(errorCode) + .build(); + } + + private FlowPathService newService() { + FlowPathService service = new FlowPathService(carrier); + service.activate(); + return service; + } + + private FlowSegmentRequestMetaFactory newFlowSegmentRequestMetaFactory() { + Cookie cookie = FlowSegmentCookie.builder() + .flowEffectiveId(0x1234) + .direction(FlowPathDirection.FORWARD) + .build(); + return new FlowSegmentRequestMetaFactory("dummy-flow", cookie, 1001); + } + + private FlowPathRequest newTwoChunkFlowPathRequest() { + return FlowPathRequest.builder() + .flowId(flowSegmentRequestMetaFactory.getFlowId()) + .pathId(new PathId("test-path-id")) + .canRevertOnError(true) + .pathChunk(new FlowPathChunk(PathChunkType.NOT_INGRESS, Arrays.asList(transitSegment, egressSegment))) + .pathChunk(new FlowPathChunk(PathChunkType.INGRESS, Collections.singletonList(ingressSegment))) + .build(); + } + + @Value + private static class SpeakerFlowSegmentReference { + Class klass; + SwitchId switchId; + + boolean isMatch(SpeakerRequest request) { + return klass.isInstance(request) && Objects.equal(switchId, request.getSwitchId()); + } + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/FlowSegmentRequestMetaFactory.java b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/FlowSegmentRequestMetaFactory.java new file mode 100644 index 00000000000..ad89ad0c75e --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/FlowSegmentRequestMetaFactory.java @@ -0,0 +1,94 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.utils; + +import org.openkilda.floodlight.api.request.factory.EgressFlowSegmentRequestFactory; +import org.openkilda.floodlight.api.request.factory.IngressFlowSegmentRequestFactory; +import org.openkilda.floodlight.api.request.factory.TransitFlowSegmentRequestFactory; +import org.openkilda.floodlight.model.FlowSegmentMetadata; +import org.openkilda.floodlight.model.RulesContext; +import org.openkilda.messaging.MessageContext; +import org.openkilda.model.FlowEncapsulationType; +import org.openkilda.model.FlowEndpoint; +import org.openkilda.model.FlowTransitEncapsulation; +import org.openkilda.model.MeterConfig; +import org.openkilda.model.MeterId; +import org.openkilda.model.SwitchId; +import org.openkilda.model.cookie.Cookie; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class FlowSegmentRequestMetaFactory { + private FlowSegmentMetadata metadata; + + private MessageContext messageContext; + + private FlowTransitEncapsulation encapsulation; + + private SequentialNumberGenerator meterIdGenerator = new SequentialNumberGenerator(); + + public FlowSegmentRequestMetaFactory(String flowId, Cookie cookie, int vlanId) { + this(new FlowSegmentMetadata(flowId, cookie, false), new MessageContext(), + new FlowTransitEncapsulation(vlanId, FlowEncapsulationType.TRANSIT_VLAN)); + } + + public FlowSegmentRequestMetaFactory( + FlowSegmentMetadata metadata, MessageContext messageContext, FlowTransitEncapsulation encapsulation) { + this.metadata = metadata; + this.messageContext = messageContext; + this.encapsulation = encapsulation; + } + + /** + * Produce {@link IngressFlowSegmentRequestFactory}. + */ + public IngressFlowSegmentRequestFactory produceIngressSegmentFactory( + Long bandwidth, FlowEndpoint endpoint, int islPort, SwitchId egressSwitchId) { + MeterConfig meterConfig = null; + if (bandwidth != null && 0 < bandwidth) { + MeterId meterId = new MeterId(meterIdGenerator.generateLong()); + meterConfig = new MeterConfig(meterId, bandwidth); + } + return new IngressFlowSegmentRequestFactory( + messageContext, metadata, endpoint, meterConfig, egressSwitchId, islPort, encapsulation, + new RulesContext(), null); + } + + /** + * Produce {@link TransitFlowSegmentRequestFactory}. + */ + public TransitFlowSegmentRequestFactory produceTransitSegmentFactory( + SwitchId switchId, int ingressIslPort, int egressIslPort) { + return new TransitFlowSegmentRequestFactory( + messageContext, switchId, metadata, ingressIslPort, egressIslPort, encapsulation); + } + + /** + * Produce {@link EgressFlowSegmentRequestFactory}. + */ + public EgressFlowSegmentRequestFactory produceEgressSegmentFactory( + FlowEndpoint endpoint, int islPort, FlowEndpoint ingressEndpoint) { + return new EgressFlowSegmentRequestFactory( + messageContext, metadata, endpoint, ingressEndpoint, islPort, encapsulation, null); + } + + public String getFlowId() { + return metadata.getFlowId(); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/SequentialNumberGenerator.java b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/SequentialNumberGenerator.java new file mode 100644 index 00000000000..f80822a013f --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/utils/SequentialNumberGenerator.java @@ -0,0 +1,51 @@ +/* Copyright 2022 Telstra Open Source + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openkilda.wfm.topology.utils; + +public class SequentialNumberGenerator { + private final long lowerLimit; + private final long upperLimit; + private long value; + + public SequentialNumberGenerator() { + this(0, Long.MAX_VALUE); + } + + public SequentialNumberGenerator(long lowerLimit, long upperLimit) { + if (upperLimit <= lowerLimit) { + throw new IllegalArgumentException(String.format( + "upper limit is less or equal lower limit (%d <= %d)", upperLimit, lowerLimit)); + } + + this.lowerLimit = value = lowerLimit; + this.upperLimit = upperLimit; + } + + /** + * Generate next long value. + */ + public long generateLong() { + long result = value; + if (upperLimit <= ++value) { + value = lowerLimit; + } + return result; + } + + public int generateInt() { + return (int) generateLong(); + } +} diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java index 29a01dd9df7..7ab4d913c97 100644 --- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java +++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java @@ -32,6 +32,7 @@ import org.openkilda.messaging.command.flow.FlowRequest; import org.openkilda.messaging.command.flow.FlowRequest.Type; import org.openkilda.messaging.command.flow.FlowRerouteRequest; +import org.openkilda.messaging.command.flow.FlowSyncRequest; import org.openkilda.messaging.command.flow.FlowValidationRequest; import org.openkilda.messaging.command.flow.SwapFlowEndpointRequest; import org.openkilda.messaging.error.ErrorType; @@ -584,19 +585,29 @@ public CompletableFuture swapFlowPaths(String flowId) { .thenApply(flowMapper::toFlowResponseOutput); } - /** - * {@inheritDoc} - */ @Override public CompletableFuture rerouteFlow(String flowId) { - logger.info("Reroute flow request for flow {}", flowId); - return reroute(flowId, false); + logger.info("Reroute flow: {}={}", FLOW_ID, flowId); + + FlowRerouteRequest payload = createManualFlowRerouteRequest(flowId, false, false, "initiated via Northbound"); + CommandMessage command = new CommandMessage( + payload, System.currentTimeMillis(), RequestCorrelationId.getId()); + + return messagingChannel.sendAndGet(rerouteTopic, command) + .thenApply(FlowRerouteResponse.class::cast) + .thenApply(response -> + flowMapper.toReroutePayload(flowId, response.getPayload(), response.isRerouted())); } @Override public CompletableFuture syncFlow(String flowId) { - logger.info("Forced reroute request for flow {}", flowId); - return reroute(flowId, true); + logger.info("Sync flow {}", flowId); + FlowSyncRequest payload = new FlowSyncRequest(flowId); + CommandMessage command = new CommandMessage(payload, System.currentTimeMillis(), RequestCorrelationId.getId()); + return messagingChannel.sendAndGet(flowHsTopic, command) + .thenApply(FlowRerouteResponse.class::cast) + .thenApply(response -> + flowMapper.toReroutePayload(flowId, response.getPayload(), response.isRerouted())); } /** @@ -655,19 +666,6 @@ public CompletableFuture rerouteFlowV2(String flowId) { flowMapper.toRerouteResponseV2(flowId, response.getPayload(), response.isRerouted())); } - private CompletableFuture reroute(String flowId, boolean forced) { - logger.debug("Reroute flow: {}={}, forced={}", FLOW_ID, flowId, forced); - String correlationId = RequestCorrelationId.getId(); - FlowRerouteRequest payload = createManualFlowRerouteRequest(flowId, forced, false, "initiated via Northbound"); - CommandMessage command = new CommandMessage( - payload, System.currentTimeMillis(), correlationId, Destination.WFM); - - return messagingChannel.sendAndGet(rerouteTopic, command) - .thenApply(FlowRerouteResponse.class::cast) - .thenApply(response -> - flowMapper.toReroutePayload(flowId, response.getPayload(), response.isRerouted())); - } - @Override public CompletableFuture> listFlowEvents(String flowId, long timestampFrom, diff --git a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java index 00a71f5e002..8a48bcbd40a 100644 --- a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java +++ b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java @@ -603,7 +603,6 @@ public void processManualRerouteRequest() { .priority(regularFlow.getPriority()) .timeCreate(regularFlow.getTimeCreate()) .affectedIsl(Collections.emptySet()) - .force(true) .effectivelyDown(true) .reason("reason") .build(); diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowSyncSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowSyncSpec.groovy index 537012ede08..0bba7a8c7a9 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowSyncSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowSyncSpec.groovy @@ -19,6 +19,7 @@ import org.openkilda.model.cookie.CookieBase.CookieType import org.openkilda.testing.model.topology.TopologyDefinition.Switch import groovy.time.TimeCategory +import spock.lang.Ignore import spock.lang.Shared class FlowSyncSpec extends HealthCheckSpecification { @@ -77,6 +78,7 @@ class FlowSyncSpec extends HealthCheckSpecification { } @Tidy + @Ignore("After PR4817 flow sync never change existing paths") def "Able to synchronize a flow (install missing flow rules, reinstall existing) with rerouting"() { given: "An intermediate-switch flow with two possible paths at least and deleted rules on src switch" def switchPair = topologyHelper.getAllNotNeighboringSwitchPairs().find { it.paths.size() > 1 } ?: diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowValidationNegativeSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowValidationNegativeSpec.groovy index 2b60a856db8..970dfdf8d52 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowValidationNegativeSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/FlowValidationNegativeSpec.groovy @@ -137,7 +137,7 @@ class FlowValidationNegativeSpec extends HealthCheckSpecification { [ description: "synchronize", operation: { getNorthbound().synchronizeFlow(NON_EXISTENT_FLOW_ID) }, - message: "Could not reroute flow", + message: "Could not sync flow", errorDescr: "Flow $NON_EXISTENT_FLOW_ID not found" ], [ From 62226eee8aee1ce5065af63342ffcc323b27f5f0 Mon Sep 17 00:00:00 2001 From: rozdy Date: Tue, 31 May 2022 17:03:26 +0300 Subject: [PATCH 4/8] Update rule manager docs Add install isl service rules sequence diagram --- .../rule-manager/implementation-details.md | 12 +++- .../design/rule-manager/isl-service-rules.png | Bin 0 -> 108864 bytes .../rule-manager/isl-service-rules.puml | 55 ++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 docs/design/rule-manager/isl-service-rules.png create mode 100644 docs/design/rule-manager/isl-service-rules.puml diff --git a/docs/design/rule-manager/implementation-details.md b/docs/design/rule-manager/implementation-details.md index ad6a2979f71..195f130aed1 100644 --- a/docs/design/rule-manager/implementation-details.md +++ b/docs/design/rule-manager/implementation-details.md @@ -1,8 +1,10 @@ # Implementation details for RuleManager library Facade of RuleManager lib is implemented as an interface with two methods: -1. buildRulesForPaths(SwitchId switchId, DataAdapter adapter) -2. buildRulesForSwitch(PathId flowPathId, DataAdapter adapter) +1. buildRulesForSwitch(SwitchId switchId, DataAdapter adapter) +2. buildRulesForPath(FlowPath flowPath, boolean filterOutUsedSharedRules, DataAdapter adapter) +3. buildRulesForYFlow(List flowPaths, DataAdapter adapter) +4. buildIslServiceRules(SwitchId switchId, int port, DataAdapter adapter) ![Class diagram](class-diagram.png "class diagram") @@ -10,4 +12,8 @@ Different adapter implementations may query database or read a file under the ho To generate service rules generators hierarchy (similar to current SwitchManager implementation) is used but the logic is moved from floodlight to RuleManager lib and result is in custom Command format. To generate flow related rules similar way is introduced. Custom Command format is close to OpenFlow format to simplify translation in speaker. -From floodlight perspective 3 new SpeakerCommands added: InstallCommand, VerifyCommand and RemoveCommand. Each command contains only one Command. Commands should be sent to speaker one by one or using a batch grouped by target switch. Floodlight should translate custom Commands into loxigen OpenFlow representation, send it to devices and process results. RuleManager returns collection of Commands with dependencies and the calling component (Flow-HS or SwitchManager) is responsible for encapsulating and sending this commands into floodlight in right order and correct batch options. +From floodlight perspective 3 new SpeakerCommands added: InstallSpeakerCommandsRequest, ModifySpeakerCommandsRequest and DeleteSpeakerCommandsRequest. Each request contains a collection of Commands of the same type (install/modify/delete). Commands inside collection may have dependepcies on each other. Requests should be sent to speaker one by one. Floodlight should build dependency tree, check it for errors (missing dependency, cycles etc), split collection to execution stages according to dependency, translate custom Commands into loxigen OpenFlow representation, send it to devices and process results. + +RuleManager returns collection of Commands and the calling component (Flow-HS/SwitchManager/Network) is responsible for encapsulating and sending this commands into floodlight in right order and correct batch options. + +![Install/delete service isl rules sequence diagram](isl-service-rules.png "Install/delete service isl rules sequence diagram") diff --git a/docs/design/rule-manager/isl-service-rules.png b/docs/design/rule-manager/isl-service-rules.png new file mode 100644 index 0000000000000000000000000000000000000000..50d475ec06eb2505bf7c8a0a0813d283b0d17505 GIT binary patch literal 108864 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
`C1 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 PVd0b&)a6TMZw387K-iYK literal 0 HcmV?d00001 diff --git a/docs/design/rule-manager/isl-service-rules.puml b/docs/design/rule-manager/isl-service-rules.puml new file mode 100644 index 00000000000..95dd748ec49 --- /dev/null +++ b/docs/design/rule-manager/isl-service-rules.puml @@ -0,0 +1,55 @@ +@startuml +title Service isl rules installation + +box "Network topology" #LightBlue +participant NetworkIslService +participant carrier +participant IslRuleService +participant RuleManager +participant SpeakerRulesWorker +end box +control speaker.topic +control network.speaker.topic +participant Floodlight + +== Install service isl rules == + +NetworkIslService -> carrier : SpeakerRulesIslInstallCommand +carrier -> IslRuleService : SpeakerRulesIslInstallCommand +IslRuleService -> RuleManager : create isl service rules +RuleManager -> IslRuleService : SpeakerData +activate IslRuleService +IslRuleService -> IslRuleService : form InstallSpeakerCommandsRequest +IslRuleService -> carrier : InstallSpeakerCommandsRequest +deactivate IslRuleService +carrier -> SpeakerRulesWorker : InstallSpeakerCommandsRequest +SpeakerRulesWorker -> speaker.topic : InstallSpeakerCommandsRequest +speaker.topic -> Floodlight : InstallSpeakerCommandsRequest +Floodlight -> network.speaker.topic : SpeakerCommandResponse +network.speaker.topic -> SpeakerRulesWorker +SpeakerRulesWorker -> carrier : SpeakerCommandResponse +carrier -> IslRuleService : SpeakerCommandResponse +IslRuleService -> carrier : IslDefaultRuleCreatedCommand +carrier -> NetworkIslService : IslDefaultRuleCreatedCommand + +== Delete service isl rules == + +NetworkIslService -> carrier : SpeakerRulesIslRemoveCommand +carrier -> IslRuleService : SpeakerRulesIslRemoveCommand +IslRuleService -> RuleManager : create isl service rules +RuleManager -> IslRuleService : SpeakerData +activate IslRuleService +IslRuleService -> IslRuleService : form DeleteSpeakerCommandsRequest +IslRuleService -> carrier : DeleteSpeakerCommandsRequest +deactivate IslRuleService +carrier -> SpeakerRulesWorker : DeleteSpeakerCommandsRequest +SpeakerRulesWorker -> speaker.topic : DeleteSpeakerCommandsRequest +speaker.topic -> Floodlight : DeleteSpeakerCommandsRequest +Floodlight -> network.speaker.topic : SpeakerCommandResponse +network.speaker.topic -> SpeakerRulesWorker +SpeakerRulesWorker -> carrier : SpeakerCommandResponse +carrier -> IslRuleService : SpeakerCommandResponse +IslRuleService -> carrier : IslDefaultRuleRemovedommand +carrier -> NetworkIslService : IslDefaultRuleRemovedCommand + +@enduml From 52b74f6f5baa5af813162994593017510023b503 Mon Sep 17 00:00:00 2001 From: Sergii Iakovenko Date: Wed, 25 May 2022 11:46:25 +0300 Subject: [PATCH 5/8] Return diversity info in get paths response. --- .../wfm/share/mappers/FlowPathMapper.java | 6 + .../command/yflow/YFlowPathsResponse.java | 2 + .../actions/ResourcesAllocationAction.java | 38 ++-- .../fsm/update/actions/UpdateFlowAction.java | 35 ++- .../actions/OnSubFlowAllocatedAction.java | 3 +- .../topology/flowhs/mapper/YFlowMapper.java | 5 +- .../service/yflow/YFlowReadService.java | 117 ++++++++-- .../service/yflow/YFlowReadServiceTest.java | 8 +- .../repositories/YFlowRepository.java | 2 + .../repositories/FermaFlowRepository.java | 20 +- .../repositories/FermaYFlowRepository.java | 26 +++ .../services/FlowOperationsService.java | 29 ++- .../northbound/dto/v2/yflows/SubFlowPath.java | 2 + .../northbound/dto/v2/yflows/YFlowPath.java | 3 + .../northbound/converter/YFlowMapper.java | 73 +++++- .../flows/yflows/YFlowDiversitySpec.groovy | 215 ++++++++++++++++-- 16 files changed, 465 insertions(+), 119 deletions(-) diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/mappers/FlowPathMapper.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/mappers/FlowPathMapper.java index 28b5d1184ca..2e5ef065706 100644 --- a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/mappers/FlowPathMapper.java +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/mappers/FlowPathMapper.java @@ -117,6 +117,9 @@ public List mapToPathNodes(NetworkEndpoint ingress, List mapToPathNodes(NetworkEndpoint ingress, List subFlowPaths; + Map> diverseWithFlows; } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/ResourcesAllocationAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/ResourcesAllocationAction.java index 323f4d274ba..67c0829a48e 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/ResourcesAllocationAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/ResourcesAllocationAction.java @@ -76,13 +76,11 @@ import org.apache.commons.lang3.StringUtils; import java.time.Duration; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; -import java.util.stream.Stream; @Slf4j public class ResourcesAllocationAction extends @@ -176,7 +174,7 @@ private void createFlow(RequestedFlow targetFlow) throws FlowNotFoundException, transactionManager.doInTransaction(() -> { Flow flow = RequestedFlowMapper.INSTANCE.toFlow(targetFlow); flow.setStatus(FlowStatus.IN_PROGRESS); - getFlowDiverseGroupFromContext(targetFlow.getDiverseFlowId()) + getOrCreateFlowDiverseGroup(targetFlow.getDiverseFlowId()) .ifPresent(flow::setDiverseGroupId); getFlowAffinityGroupFromContext(targetFlow.getAffinityFlowId()) .ifPresent(flow::setAffinityGroupId); @@ -211,21 +209,21 @@ private void createFlow(RequestedFlow targetFlow) throws FlowNotFoundException, } } - private Optional getFlowDiverseGroupFromContext(String diverseFlowId) throws FlowNotFoundException { - if (StringUtils.isNotBlank(diverseFlowId)) { - String flowId = yFlowRepository.findById(diverseFlowId).map(Stream::of).orElseGet(Stream::empty) - .map(YFlow::getSubFlows) - .flatMap(Collection::stream) - .map(YSubFlow::getFlow) - .filter(flow -> flow.getFlowId().equals(flow.getAffinityGroupId())) - .map(Flow::getFlowId) - .findFirst() - .orElse(diverseFlowId); - return flowRepository.getOrCreateDiverseFlowGroupId(flowId) - .map(Optional::of) - .orElseThrow(() -> new FlowNotFoundException(flowId)); + private Optional getOrCreateFlowDiverseGroup(String diverseFlowId) throws FlowNotFoundException { + if (StringUtils.isBlank(diverseFlowId)) { + return Optional.empty(); } - return Optional.empty(); + Optional groupId; + if (yFlowRepository.exists(diverseFlowId)) { + groupId = yFlowRepository.getOrCreateDiverseYFlowGroupId(diverseFlowId); + } else if (yFlowRepository.isSubFlow(diverseFlowId)) { + groupId = flowRepository.findById(diverseFlowId) + .map(Flow::getYFlowId) + .flatMap(yFlowRepository::getOrCreateDiverseYFlowGroupId); + } else { + groupId = flowRepository.getOrCreateDiverseFlowGroupId(diverseFlowId); + } + return Optional.of(groupId.orElseThrow(() -> new FlowNotFoundException(diverseFlowId))); } private Optional getFlowAffinityGroupFromContext(String affinityFlowId) throws FlowNotFoundException { @@ -330,8 +328,10 @@ private void allocateProtectedPath(FlowCreateFsm stateMachine) throws Unroutable if (!tmpFlow.isAllocateProtectedPath()) { return; } - tmpFlow.setDiverseGroupId(getFlowDiverseGroupFromContext(flowId) - .orElseThrow(() -> new FlowNotFoundException(flowId))); + if (tmpFlow.getDiverseGroupId() == null) { + tmpFlow.setDiverseGroupId(flowRepository.getOrCreateDiverseFlowGroupId(flowId) + .orElseThrow(() -> new FlowNotFoundException(flowId))); + } GetPathsResult protectedPath = pathComputer.getPath(tmpFlow); stateMachine.setBackUpProtectedPathComputationWayUsed(protectedPath.isBackUpPathComputationWayUsed()); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/actions/UpdateFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/actions/UpdateFlowAction.java index 6dd33568a16..2f1c36d1143 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/actions/UpdateFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/actions/UpdateFlowAction.java @@ -22,8 +22,6 @@ import org.openkilda.model.DetectConnectedDevices; import org.openkilda.model.Flow; import org.openkilda.model.Switch; -import org.openkilda.model.YFlow; -import org.openkilda.model.YSubFlow; import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.RepositoryFactory; import org.openkilda.persistence.repositories.SwitchRepository; @@ -45,9 +43,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.storm.shade.com.google.common.base.Objects; -import java.util.Collection; import java.util.Optional; -import java.util.stream.Stream; @Slf4j public class UpdateFlowAction extends @@ -120,11 +116,13 @@ private RequestedFlow updateFlow(Flow flow, RequestedFlow targetFlow) { if (targetFlow.getDiverseFlowId().isEmpty()) { flow.setDiverseGroupId(null); } else { - flow.setDiverseGroupId(getOrCreateDiverseFlowGroupId(targetFlow.getDiverseFlowId())); + flow.setDiverseGroupId(getOrCreateFlowDiverseGroup(targetFlow.getDiverseFlowId())); } } else if (targetFlow.isAllocateProtectedPath()) { if (flow.getDiverseGroupId() == null) { - flow.setDiverseGroupId(getOrCreateDiverseFlowGroupId(flow.getFlowId())); + flow.setDiverseGroupId(flowRepository.getOrCreateDiverseFlowGroupId(flow.getFlowId()) + .orElseThrow(() -> new FlowProcessingException(ErrorType.NOT_FOUND, + format("Diverse flow %s not found", flow.getFlowId())))); } } @@ -197,19 +195,20 @@ private RequestedFlow updateFlow(Flow flow, RequestedFlow targetFlow) { return targetFlow; } - private String getOrCreateDiverseFlowGroupId(String diverseFlowId) throws FlowProcessingException { + private String getOrCreateFlowDiverseGroup(String diverseFlowId) throws FlowProcessingException { log.debug("Getting flow diverse group for flow with id {}", diverseFlowId); - String flowId = yFlowRepository.findById(diverseFlowId).map(Stream::of).orElseGet(Stream::empty) - .map(YFlow::getSubFlows) - .flatMap(Collection::stream) - .map(YSubFlow::getFlow) - .filter(flow -> flow.getFlowId().equals(flow.getAffinityGroupId())) - .map(Flow::getFlowId) - .findFirst() - .orElse(diverseFlowId); - return flowRepository.getOrCreateDiverseFlowGroupId(flowId) - .orElseThrow(() -> new FlowProcessingException(ErrorType.NOT_FOUND, - format("Flow %s not found", flowId))); + Optional groupId; + if (yFlowRepository.exists(diverseFlowId)) { + groupId = yFlowRepository.getOrCreateDiverseYFlowGroupId(diverseFlowId); + } else if (yFlowRepository.isSubFlow(diverseFlowId)) { + groupId = flowRepository.findById(diverseFlowId) + .map(Flow::getYFlowId) + .flatMap(yFlowRepository::getOrCreateDiverseYFlowGroupId); + } else { + groupId = flowRepository.getOrCreateDiverseFlowGroupId(diverseFlowId); + } + return groupId.orElseThrow(() -> new FlowProcessingException(ErrorType.NOT_FOUND, + format("Diverse flow %s not found", diverseFlowId))); } private String getOrCreateAffinityFlowGroupId(String flowId) throws FlowProcessingException { diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/OnSubFlowAllocatedAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/OnSubFlowAllocatedAction.java index f8e2155dd9d..4266af9cc0e 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/OnSubFlowAllocatedAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/OnSubFlowAllocatedAction.java @@ -74,12 +74,13 @@ protected Optional performWithResponse(State from, State to, Event even stateMachine.addCreatingSubFlow(requestedFlowId); stateMachine.notifyEventListeners(listener -> listener.onSubFlowProcessingStart(yFlowId, requestedFlowId)); - CommandContext flowContext = stateMachine.getCommandContext().fork(requestedFlowId); if (!requestedFlow.getSrcSwitch().equals(requestedFlow.getDestSwitch())) { // One-switch flow can't be added to an affinity group. requestedFlow.setAffinityFlowId(stateMachine.getMainAffinityFlowId()); } + requestedFlow.setDiverseFlowId(stateMachine.getDiverseFlowId()); requestedFlow.setYFlowId(stateMachine.getYFlowId()); + CommandContext flowContext = stateMachine.getCommandContext().fork(requestedFlowId); flowCreateService.startFlowCreation(flowContext, requestedFlow, yFlowId); } }); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/mapper/YFlowMapper.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/mapper/YFlowMapper.java index 9e314470a43..a6872c4a58a 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/mapper/YFlowMapper.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/mapper/YFlowMapper.java @@ -105,8 +105,9 @@ public SubFlowDto toSubFlowDto(YSubFlow subFlow) { protected Collection getDiverseWithFlow(Flow flow, FlowRepository flowRepository) { return flow.getDiverseGroupId() == null ? Collections.emptyList() : flowRepository.findByDiverseGroupId(flow.getDiverseGroupId()).stream() - .filter(diverseFlow -> !flow.getFlowId().equals(diverseFlow.getFlowId()) - || (flow.getYFlowId() != null && !flow.getYFlowId().equals(diverseFlow.getYFlowId()))) + .filter(diverseFlow -> !flow.getFlowId().equals(diverseFlow.getFlowId())) + .filter(diverseFlow -> flow.getYFlowId() == null + || !flow.getYFlowId().equals(diverseFlow.getYFlowId())) .collect(Collectors.toSet()); } } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadService.java index 8cff91ffa55..9f4679a0591 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadService.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadService.java @@ -32,7 +32,9 @@ import org.openkilda.model.YSubFlow; import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.exceptions.PersistenceException; +import org.openkilda.persistence.repositories.FlowPathRepository; import org.openkilda.persistence.repositories.FlowRepository; +import org.openkilda.persistence.repositories.RepositoryFactory; import org.openkilda.persistence.repositories.YFlowRepository; import org.openkilda.persistence.tx.TransactionManager; import org.openkilda.wfm.error.FlowNotFoundException; @@ -47,8 +49,10 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -56,15 +60,18 @@ public class YFlowReadService { private final YFlowRepository yFlowRepository; private final FlowRepository flowRepository; + private final FlowPathRepository flowPathRepository; private final TransactionManager transactionManager; private final int readOperationRetriesLimit; private final Duration readOperationRetryDelay; public YFlowReadService(@NonNull PersistenceManager persistenceManager, int readOperationRetriesLimit, @NonNull Duration readOperationRetryDelay) { - this.yFlowRepository = persistenceManager.getRepositoryFactory().createYFlowRepository(); - this.flowRepository = persistenceManager.getRepositoryFactory().createFlowRepository(); - this.transactionManager = persistenceManager.getTransactionManager(); + RepositoryFactory repositoryFactory = persistenceManager.getRepositoryFactory(); + yFlowRepository = repositoryFactory.createYFlowRepository(); + flowRepository = repositoryFactory.createFlowRepository(); + flowPathRepository = repositoryFactory.createFlowPathRepository(); + transactionManager = persistenceManager.getTransactionManager(); this.readOperationRetriesLimit = readOperationRetriesLimit; this.readOperationRetryDelay = readOperationRetryDelay; } @@ -114,35 +121,59 @@ public YFlowPathsResponse getYFlowPaths(@NonNull String yFlowId) throws FlowNotF Set protectedForwardPaths = new HashSet<>(); Set protectedReversePaths = new HashSet<>(); List subFlowPathDtos = new ArrayList<>(); + Map> diverseWithFlows = new HashMap<>(); + for (YSubFlow subFlow : yFlow.getSubFlows()) { Flow flow = subFlow.getFlow(); if (!flow.isOneSwitchFlow()) { mainForwardPaths.add(flow.getForwardPath()); mainReversePaths.add(flow.getReversePath()); } - FlowPathDto.FlowPathDtoBuilder pathDtoBuilder = FlowPathDto.builder() - .id(flow.getFlowId()) - .forwardPath(FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getForwardPath())) - .reversePath(FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getReversePath())); - + FlowPathDto.FlowPathDtoBuilder pathDtoBuilder = buildFlowPathDto(flow); + FlowProtectedPathDto.FlowProtectedPathDtoBuilder protectedDtoBuilder = null; if (flow.isAllocateProtectedPath()) { - FlowProtectedPathDto.FlowProtectedPathDtoBuilder protectedDtoBuilder = - FlowProtectedPathDto.builder(); - if (flow.getProtectedForwardPath() != null) { - if (!flow.isOneSwitchFlow()) { - protectedForwardPaths.add(flow.getProtectedForwardPath()); - } - protectedDtoBuilder.forwardPath( - FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getProtectedForwardPath())); - + protectedDtoBuilder = buildFlowProtectedPathDto(flow); + if (flow.getProtectedForwardPath() != null && !flow.isOneSwitchFlow()) { + protectedForwardPaths.add(flow.getProtectedForwardPath()); } - if (flow.getProtectedReversePath() != null) { - if (!flow.isOneSwitchFlow()) { - protectedReversePaths.add(flow.getProtectedReversePath()); - } - protectedDtoBuilder.reversePath( - FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getProtectedReversePath())); + if (flow.getProtectedReversePath() != null && !flow.isOneSwitchFlow()) { + protectedReversePaths.add(flow.getProtectedReversePath()); + } + } + + String diverseGroupId = flow.getDiverseGroupId(); + if (diverseGroupId != null) { + Collection flowPathsInDiverseGroup = flowPathRepository.findByFlowGroupId(diverseGroupId); + IntersectionComputer primaryIntersectionComputer = new IntersectionComputer( + flow.getFlowId(), flow.getForwardPathId(), flow.getReversePathId(), + flowPathsInDiverseGroup); + pathDtoBuilder.segmentsStats(primaryIntersectionComputer.getOverlappingStats()); + + Collection flowsInDiverseGroup = flowRepository.findByDiverseGroupId(diverseGroupId).stream() + .filter(f -> !flow.getFlowId().equals(f.getFlowId())) + .collect(Collectors.toList()); + + List groupFlowsWithOverlappingStats = new ArrayList<>(); + flowsInDiverseGroup.stream() + .map(diverseFlow -> buildGroupPathFlowDto(diverseFlow, true, primaryIntersectionComputer)) + .forEach(groupFlowsWithOverlappingStats::add); + + if (protectedDtoBuilder != null) { + IntersectionComputer protectedIntersectionComputer = new IntersectionComputer( + flow.getFlowId(), flow.getProtectedForwardPathId(), flow.getProtectedReversePathId(), + flowPathsInDiverseGroup); + protectedDtoBuilder.segmentsStats(protectedIntersectionComputer.getOverlappingStats()); + + flowsInDiverseGroup.stream() + .map(diverseFlow -> + buildGroupPathFlowDto(diverseFlow, false, protectedIntersectionComputer)) + .forEach(groupFlowsWithOverlappingStats::add); } + + diverseWithFlows.put(flow.getFlowId(), groupFlowsWithOverlappingStats); + } + + if (protectedDtoBuilder != null) { pathDtoBuilder.protectedPath(protectedDtoBuilder.build()); } subFlowPathDtos.add(pathDtoBuilder.build()); @@ -181,10 +212,48 @@ public YFlowPathsResponse getYFlowPaths(@NonNull String yFlowId) throws FlowNotF sharedPath.setProtectedPath(protectedDtoBuilder.build()); } - return new YFlowPathsResponse(sharedPath, subFlowPathDtos); + return new YFlowPathsResponse(sharedPath, subFlowPathDtos, diverseWithFlows); }); } + private FlowPathDto.FlowPathDtoBuilder buildFlowPathDto(Flow flow) { + return FlowPathDto.builder() + .id(flow.getFlowId()) + .forwardPath(FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getForwardPath())) + .reversePath(FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getReversePath())); + } + + private FlowProtectedPathDto.FlowProtectedPathDtoBuilder buildFlowProtectedPathDto(Flow flow) { + FlowProtectedPathDto.FlowProtectedPathDtoBuilder protectedDtoBuilder = + FlowProtectedPathDto.builder(); + if (flow.getProtectedForwardPath() != null) { + protectedDtoBuilder.forwardPath( + FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getProtectedForwardPath())); + + } + if (flow.getProtectedReversePath() != null) { + protectedDtoBuilder.reversePath( + FlowPathMapper.INSTANCE.mapToPathNodes(flow, flow.getProtectedReversePath())); + } + return protectedDtoBuilder; + } + + private FlowPathDto buildGroupPathFlowDto(Flow flow, boolean primaryPathCorrespondStat, + IntersectionComputer intersectionComputer) { + FlowPathDto.FlowPathDtoBuilder builder = buildFlowPathDto(flow) + .primaryPathCorrespondStat(primaryPathCorrespondStat) + .segmentsStats( + intersectionComputer.getOverlappingStats(flow.getForwardPathId(), flow.getReversePathId())); + if (flow.isAllocateProtectedPath()) { + FlowProtectedPathDto.FlowProtectedPathDtoBuilder protectedPathBuilder = buildFlowProtectedPathDto(flow) + .segmentsStats( + intersectionComputer.getOverlappingStats( + flow.getProtectedForwardPathId(), flow.getProtectedReversePathId())); + builder.protectedPath(protectedPathBuilder.build()); + } + return builder.build(); + } + /** * Gets y-flow sub-flows. */ diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadServiceTest.java b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadServiceTest.java index c3942a0fd61..5caadfd0259 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadServiceTest.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/yflow/YFlowReadServiceTest.java @@ -112,7 +112,7 @@ public void shouldFetchYFlowPaths() throws FlowNotFoundException { YFlowPathsResponse yFlowResponse = yFlowReadService.getYFlowPaths(yFlowId); // then // Only 1 shared segment - assertEquals(1, yFlowResponse.getSharedPath().getForwardPath().size()); + assertEquals(2, yFlowResponse.getSharedPath().getForwardPath().size()); assertEquals(SWITCH_SHARED, yFlowResponse.getSharedPath().getForwardPath().get(0).getSwitchId()); assertEquals(2, yFlowResponse.getSubFlowPaths().size()); // No protected paths @@ -143,11 +143,13 @@ public void shouldFetchYFlowWithProtectedPaths() throws FlowNotFoundException { YFlowPathsResponse yFlowPathsResponse = yFlowReadService.getYFlowPaths(yFlowId); // then // Only 1 shared segment - assertEquals(1, yFlowPathsResponse.getSharedPath().getForwardPath().size()); + assertEquals(2, yFlowPathsResponse.getSharedPath().getForwardPath().size()); + assertEquals(2, yFlowPathsResponse.getSharedPath().getReversePath().size()); assertEquals(SWITCH_SHARED, yFlowPathsResponse.getSharedPath().getForwardPath().get(0).getSwitchId()); assertEquals(2, yFlowPathsResponse.getSubFlowPaths().size()); // The protected paths - assertEquals(1, yFlowPathsResponse.getSharedPath().getProtectedPath().getForwardPath().size()); + assertEquals(2, yFlowPathsResponse.getSharedPath().getProtectedPath().getForwardPath().size()); + assertEquals(2, yFlowPathsResponse.getSharedPath().getProtectedPath().getReversePath().size()); assertEquals(SWITCH_SHARED, yFlowPathsResponse.getSharedPath().getProtectedPath().getForwardPath().get(0).getSwitchId()); } diff --git a/src-java/kilda-persistence-api/src/main/java/org/openkilda/persistence/repositories/YFlowRepository.java b/src-java/kilda-persistence-api/src/main/java/org/openkilda/persistence/repositories/YFlowRepository.java index 9271fe11511..00da53c120f 100644 --- a/src-java/kilda-persistence-api/src/main/java/org/openkilda/persistence/repositories/YFlowRepository.java +++ b/src-java/kilda-persistence-api/src/main/java/org/openkilda/persistence/repositories/YFlowRepository.java @@ -35,4 +35,6 @@ public interface YFlowRepository extends Repository { Optional findYFlowId(String subFlowId); Optional remove(String yFlowId); + + Optional getOrCreateDiverseYFlowGroupId(String yFlowId); } diff --git a/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaFlowRepository.java b/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaFlowRepository.java index 16ab89bae4a..9fba3988373 100644 --- a/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaFlowRepository.java +++ b/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaFlowRepository.java @@ -404,22 +404,12 @@ public Collection findByFlowFilter(FlowFilter flowFilter) { public Optional getOrCreateDiverseFlowGroupId(String flowId) { return getTransactionManager().doInTransaction(() -> findById(flowId) .map(flow -> { - Flow diverseFlow = flow; - /*TODO: why is this required? - if (diverseFlow.getAffinityGroupId() != null) { - Optional mainAffinityFlow = findById(diverseFlow.getAffinityGroupId()); - if (mainAffinityFlow.isPresent()) { - diverseFlow = mainAffinityFlow.get(); - } else { - return null; - } - }*/ - - if (diverseFlow.getDiverseGroupId() == null) { - String groupId = UUID.randomUUID().toString(); - diverseFlow.setDiverseGroupId(groupId); + String groupId = flow.getDiverseGroupId(); + if (groupId == null) { + groupId = UUID.randomUUID().toString(); + flow.setDiverseGroupId(groupId); } - return diverseFlow.getDiverseGroupId(); + return groupId; })); } diff --git a/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaYFlowRepository.java b/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaYFlowRepository.java index 8a7ee0218d9..f15499bbb47 100644 --- a/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaYFlowRepository.java +++ b/src-java/kilda-persistence-tinkerpop/src/main/java/org/openkilda/persistence/ferma/repositories/FermaYFlowRepository.java @@ -15,8 +15,11 @@ package org.openkilda.persistence.ferma.repositories; +import static java.lang.String.format; + import org.openkilda.model.YFlow; import org.openkilda.model.YFlow.YFlowData; +import org.openkilda.model.YSubFlow; import org.openkilda.persistence.exceptions.PersistenceException; import org.openkilda.persistence.ferma.FermaPersistentImplementation; import org.openkilda.persistence.ferma.frames.KildaBaseVertexFrame; @@ -31,6 +34,7 @@ import java.util.Collection; import java.util.Optional; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -115,6 +119,28 @@ public Optional remove(String flowId) { })); } + @Override + public Optional getOrCreateDiverseYFlowGroupId(String yFlowId) { + return getTransactionManager().doInTransaction(() -> findById(yFlowId) + .map(yFlow -> { + String groupId = yFlow.getSubFlows().stream() + .map(YSubFlow::getFlow) + .filter(flow -> flow.getFlowId().equals(flow.getAffinityGroupId())) + .findFirst() + .orElseThrow(() -> new IllegalStateException( + format("Y-flow %s has no sub-flow with an affinity group defined.", yFlowId))) + .getDiverseGroupId(); + if (groupId == null) { + groupId = UUID.randomUUID().toString(); + } + for (YSubFlow ySubFlow : yFlow.getSubFlows()) { + ySubFlow.getFlow().setDiverseGroupId(groupId); + } + return groupId; + })); + } + + @Override protected YFlowFrame doAdd(YFlowData data) { YFlowFrame frame = KildaBaseVertexFrame.addNewFramedVertex(framedGraph(), YFlowFrame.FRAME_LABEL, diff --git a/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java b/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java index 067727257dd..543d2bdb06e 100644 --- a/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java +++ b/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java @@ -45,8 +45,6 @@ import org.openkilda.model.PathComputationStrategy; import org.openkilda.model.SwitchConnectedDevice; import org.openkilda.model.SwitchId; -import org.openkilda.model.YFlow; -import org.openkilda.model.YSubFlow; import org.openkilda.persistence.exceptions.PersistenceException; import org.openkilda.persistence.repositories.FlowPathRepository; import org.openkilda.persistence.repositories.FlowRepository; @@ -479,19 +477,20 @@ private boolean updateRequiredByDestination(FlowPatch flowPatch, Flow flow) { } private boolean updateRequiredByDiverseFlowIdField(FlowPatch flowPatch, Flow flow) { - if (flowPatch.getDiverseFlowId() != null) { - String diverseFlowId = yFlowRepository.findById(flowPatch.getDiverseFlowId()) - .map(Stream::of).orElseGet(Stream::empty) - .map(YFlow::getSubFlows) - .flatMap(Collection::stream) - .map(YSubFlow::getFlow) - .filter(f -> f.getFlowId().equals(f.getAffinityGroupId())) - .map(Flow::getFlowId) - .findFirst() - .orElse(flowPatch.getDiverseFlowId()); - return flowRepository.getOrCreateDiverseFlowGroupId(diverseFlowId) - .map(groupId -> !flowRepository.findFlowsIdByDiverseGroupId(groupId).contains(flow.getFlowId())) - .orElse(true); + String diverseFlowId = flowPatch.getDiverseFlowId(); + if (diverseFlowId != null) { + Optional groupId; + if (yFlowRepository.exists(diverseFlowId)) { + groupId = yFlowRepository.getOrCreateDiverseYFlowGroupId(diverseFlowId); + } else if (yFlowRepository.isSubFlow(diverseFlowId)) { + groupId = flowRepository.findById(diverseFlowId) + .map(Flow::getYFlowId) + .flatMap(yFlowRepository::getOrCreateDiverseYFlowGroupId); + } else { + groupId = flowRepository.getOrCreateDiverseFlowGroupId(diverseFlowId); + } + return !groupId.isPresent() + || !flowRepository.findFlowsIdByDiverseGroupId(groupId.get()).contains(flow.getFlowId()); } return false; } diff --git a/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/SubFlowPath.java b/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/SubFlowPath.java index ac383af2d40..97e690f2052 100644 --- a/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/SubFlowPath.java +++ b/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/SubFlowPath.java @@ -22,6 +22,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import lombok.experimental.SuperBuilder; @Data @@ -30,6 +31,7 @@ @JsonNaming(SnakeCaseStrategy.class) @JsonInclude(Include.NON_NULL) @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class SubFlowPath extends YFlowPath { String flowId; } diff --git a/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/YFlowPath.java b/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/YFlowPath.java index a426e84b3d6..eb96e8338c5 100644 --- a/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/YFlowPath.java +++ b/src-java/northbound-service/northbound-api/src/main/java/org/openkilda/northbound/dto/v2/yflows/YFlowPath.java @@ -15,6 +15,7 @@ package org.openkilda.northbound.dto.v2.yflows; +import org.openkilda.messaging.payload.flow.DiverseGroupPayload; import org.openkilda.messaging.payload.flow.PathNodePayload; import com.fasterxml.jackson.annotation.JsonInclude; @@ -38,6 +39,7 @@ public class YFlowPath { List forward; List reverse; + DiverseGroupPayload diverseGroup; YFlowProtectedPath protectedPath; @Data @@ -48,5 +50,6 @@ public class YFlowPath { public static class YFlowProtectedPath { List forward; List reverse; + DiverseGroupPayload diverseGroup; } } diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/converter/YFlowMapper.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/converter/YFlowMapper.java index 6437d0935e0..ec1c93cd2e2 100644 --- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/converter/YFlowMapper.java +++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/converter/YFlowMapper.java @@ -31,7 +31,10 @@ import org.openkilda.messaging.info.flow.YFlowPingResponse; import org.openkilda.messaging.model.FlowPathDto; import org.openkilda.messaging.model.FlowPathDto.FlowProtectedPathDto; +import org.openkilda.messaging.payload.flow.DiverseGroupPayload; import org.openkilda.messaging.payload.flow.FlowEndpointPayload; +import org.openkilda.messaging.payload.flow.GroupFlowPathPayload; +import org.openkilda.messaging.payload.flow.OverlappingSegmentsStats; import org.openkilda.model.FlowEndpoint; import org.openkilda.northbound.dto.v2.flows.FlowEndpointV2; import org.openkilda.northbound.dto.v2.flows.FlowPathV2; @@ -57,7 +60,11 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; import java.util.stream.Collectors; @Mapper(componentModel = "spring", @@ -65,6 +72,8 @@ TimeMapper.class, PingMapper.class}, imports = {FlowEndpointPayload.class, FlowEndpointV2.class}) public abstract class YFlowMapper { + @Autowired + PathMapper pathMapper; @Mapping(target = "yFlowId", source = "YFlowId") @Mapping(target = "yPoint", source = "YPoint") @@ -85,20 +94,70 @@ public abstract class YFlowMapper { public abstract YFlowSharedEndpointEncapsulation toYFlowSharedEndpointEncapsulation(FlowEndpoint endpoint); @Mapping(target = "sharedPath", source = "sharedPath", resultType = YFlowPath.class) + @Mapping(target = "subFlowPaths", + expression = "java(toSubFlowPaths(source.getSubFlowPaths(), source.getDiverseWithFlows()))") public abstract YFlowPaths toYFlowPaths(YFlowPathsResponse source); + protected List toSubFlowPaths(List subFlowPaths, + Map> diverseWithFlows) { + return subFlowPaths.stream() + .map(f -> toSubFlowPath(f, diverseWithFlows.get(f.getId()))) + .collect(Collectors.toList()); + } + @Mapping(target = "forward", source = "forwardPath") @Mapping(target = "reverse", source = "reversePath") + @Mapping(target = "protectedPath", expression = "java(toYFlowProtectedPath(source.getProtectedPath(), null))") + @Mapping(target = "diverseGroup", expression = "java(toDiverseGroupPayload(source, null))") public abstract YFlowPath toYFlowPath(FlowPathDto source); - @Mapping(target = "forward", source = "forwardPath") - @Mapping(target = "reverse", source = "reversePath") - public abstract YFlowProtectedPath toYFlowProtectedPath(FlowProtectedPathDto source); + @Mapping(target = "forward", source = "source.forwardPath") + @Mapping(target = "reverse", source = "source.reversePath") + @Mapping(target = "diverseGroup", expression = "java(toDiverseGroupPayload(source, diverseWithFlows))") + public abstract YFlowProtectedPath toYFlowProtectedPath(FlowProtectedPathDto source, + List diverseWithFlows); + + @Mapping(target = "flowId", source = "source.id") + @Mapping(target = "reverse", source = "source.reversePath") + @Mapping(target = "forward", source = "source.forwardPath") + @Mapping(target = "protectedPath", + expression = "java(toYFlowProtectedPath(source.getProtectedPath(), diverseWithFlows))") + @Mapping(target = "diverseGroup", expression = "java(toDiverseGroupPayload(source, diverseWithFlows))") + public abstract SubFlowPath toSubFlowPath(FlowPathDto source, List diverseWithFlows); + + protected DiverseGroupPayload toDiverseGroupPayload(FlowPathDto source, List diverseWithFlows) { + OverlappingSegmentsStats segmentsStats = source.getSegmentsStats(); + if (segmentsStats != null) { + return DiverseGroupPayload.builder() + .overlappingSegments(segmentsStats) + .otherFlows(diverseWithFlows != null + ? toGroupPaths(diverseWithFlows, FlowPathDto::isPrimaryPathCorrespondStat) : null) + .build(); + } + return null; + } - @Mapping(target = "flowId", source = "id") - @Mapping(target = "reverse", source = "reversePath") - @Mapping(target = "forward", source = "forwardPath") - public abstract SubFlowPath toSubFlowPath(FlowPathDto source); + protected DiverseGroupPayload toDiverseGroupPayload(FlowProtectedPathDto source, + List diverseWithFlows) { + if (source != null) { + OverlappingSegmentsStats segmentsStats = source.getSegmentsStats(); + if (segmentsStats != null) { + return DiverseGroupPayload.builder() + .overlappingSegments(segmentsStats) + .otherFlows(diverseWithFlows != null + ? toGroupPaths(diverseWithFlows, e -> !e.isPrimaryPathCorrespondStat()) : null) + .build(); + } + } + return null; + } + + private List toGroupPaths(List paths, Predicate predicate) { + return paths.stream() + .filter(predicate) + .map(pathMapper::mapGroupFlowPathPayload) + .collect(Collectors.toList()); + } @Mapping(target = "segmentLatency", source = "segLatency") public abstract FlowPathV2.PathNodeV2 toPathNodeV2(PathNode pathNode); diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowDiversitySpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowDiversitySpec.groovy index 5c610220f5c..217aa4bb70b 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowDiversitySpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowDiversitySpec.groovy @@ -10,7 +10,9 @@ import org.openkilda.functionaltests.HealthCheckSpecification import org.openkilda.functionaltests.extension.failfast.Tidy import org.openkilda.functionaltests.helpers.PathHelper import org.openkilda.functionaltests.helpers.YFlowHelper +import org.openkilda.messaging.payload.flow.FlowPathPayload import org.openkilda.northbound.dto.v2.yflows.YFlowPatchPayload +import org.openkilda.northbound.dto.v2.yflows.YFlowPaths import groovy.util.logging.Slf4j import org.springframework.beans.factory.annotation.Autowired @@ -18,14 +20,14 @@ import spock.lang.Narrative import spock.lang.Shared @Slf4j -@Narrative("Verify the ability to create diverse yflows in the system.") +@Narrative("Verify the ability to create diverse y-flows in the system.") class YFlowDiversitySpec extends HealthCheckSpecification { @Autowired @Shared YFlowHelper yFlowHelper @Tidy - def "Able to create diverse yFlows"() { + def "Able to create diverse y-flows"() { given: "Switches with three not overlapping paths at least" def swT = topologyHelper.switchTriplets.find { [it.shared, it.ep1, it.ep2].every { it.traffGens } && @@ -36,7 +38,7 @@ class YFlowDiversitySpec extends HealthCheckSpecification { } assumeTrue(swT != null, "Unable to find suitable switches") - when: "Create three flows with diversity enabled" + when: "Create three y-flows with diversity enabled" def yFlowRequest1 = yFlowHelper.randomYFlow(swT, false) def yFlow1 = yFlowHelper.addYFlow(yFlowRequest1) def yFlowRequest2 = yFlowHelper.randomYFlow(swT, false, [yFlowRequest1]) @@ -51,13 +53,13 @@ class YFlowDiversitySpec extends HealthCheckSpecification { yFlow2.diverseWithYFlows.sort() == [yFlow1.YFlowId].sort() yFlow3.diverseWithYFlows.sort() == [yFlow1.YFlowId, yFlow2.YFlowId].sort() - and: "All flows have diverse yFlow IDs in response" + and: "All y-flows have diverse yFlow IDs in response" northboundV2.getYFlow(yFlow1.YFlowId).diverseWithYFlows.sort() == [yFlow2.YFlowId, yFlow3.YFlowId].sort() northboundV2.getYFlow(yFlow2.YFlowId).diverseWithYFlows.sort() == [yFlow1.YFlowId, yFlow3.YFlowId].sort() northboundV2.getYFlow(yFlow3.YFlowId).diverseWithYFlows.sort() == [yFlow1.YFlowId, yFlow2.YFlowId].sort() - and: "All yFlows have different paths" + and: "All y-flows have different paths" def allInvolvedIsls = [yFlow1.subFlows[0], yFlow2.subFlows[0], yFlow3.subFlows[0]].collectMany { pathHelper.getInvolvedIsls(PathHelper.convert(northbound.getFlowPath(it.flowId))) } @@ -72,7 +74,7 @@ class YFlowDiversitySpec extends HealthCheckSpecification { and: "Y-flow passes flow validation" [yFlow1, yFlow2, yFlow3].each { assert northboundV2.validateYFlow(it.YFlowId).asExpected } - when: "Delete flows" + when: "Delete y-flows" [yFlow1, yFlow2, yFlow3].each { it && yFlowHelper.deleteYFlow(it.YFlowId) } def yFlowsAreDeleted = true @@ -87,7 +89,7 @@ class YFlowDiversitySpec extends HealthCheckSpecification { } @Tidy - def "Able to update yFlow to became diverse with simple multiSwitch flow"() { + def "Able to update y-flow to became diverse with simple multiSwitch flow"() { given: "Switches with two not overlapping paths at least" def swT = topologyHelper.switchTriplets.find { [it.shared, it.ep1, it.ep2].every { it.traffGens } && @@ -96,11 +98,11 @@ class YFlowDiversitySpec extends HealthCheckSpecification { } assumeTrue(swT != null, "Unable to find suitable switches") - and: "YFlow created" + and: "Y-flow created" def yFlowRequest = yFlowHelper.randomYFlow(swT, false) def yFlow = yFlowHelper.addYFlow(yFlowRequest) - and: "Simple multiSwitch flow on the same path as first subFlow" + and: "Simple multiSwitch flow on the same path as first sub-flow" def flow = flowHelperV2.randomFlow(swT.shared, swT.ep1, false) flowHelperV2.addFlow(flow) def subFlow = yFlow.subFlows.first() @@ -108,14 +110,14 @@ class YFlowDiversitySpec extends HealthCheckSpecification { def involvedIslSimpleFlow = pathHelper.getInvolvedIsls(PathHelper.convert(northbound.getFlowPath(flow.flowId))) assert involvedIslSubFlow == involvedIslSimpleFlow - when: "Update yflow to become diverse with simple multiSwitch flow" + when: "Update y-flow to become diverse with simple multiSwitch flow" def update = yFlowHelper.convertToUpdate(yFlow.tap { it.diverseWithFlows = [flow.flowId] }) def updateResponse = yFlowHelper.updateYFlow(yFlow.YFlowId, update) then: "Update response contains information about diverse flow" updateResponse.diverseWithFlows.sort() == [flow.flowId].sort() - and: "Yflow is really updated" + and: "Y-flow is really updated" with(northboundV2.getYFlow(yFlow.YFlowId)) { it.diverseWithFlows.sort() == [flow.flowId].sort() it.diverseWithYFlows.empty @@ -127,7 +129,7 @@ class YFlowDiversitySpec extends HealthCheckSpecification { it.diverseWith.empty } - and: "First sub flow became diverse and changed path" + and: "First sub-flow became diverse and changed path" def involvedIslSubFlowAfterUpdate = pathHelper.getInvolvedIsls(PathHelper.convert(northbound.getFlowPath(subFlow.flowId))) assert involvedIslSubFlowAfterUpdate != involvedIslSimpleFlow @@ -143,14 +145,14 @@ class YFlowDiversitySpec extends HealthCheckSpecification { and: "Simple flow is valid" northbound.validateFlow(flow.flowId).each { direction -> assert direction.asExpected } - when: "Partially update yflow to become not diverse with simple multiSwitch flow" - def patch = YFlowPatchPayload.builder().diverseFlowId("").build() + when: "Partially update y-flow to become not diverse with simple multiSwitch flow" + def patch = YFlowPatchPayload.builder().diverseFlowId("").build() def patchResponse = yFlowHelper.partialUpdateYFlow(yFlow.YFlowId, patch) then: "Update response contains information about diverse flow" patchResponse.diverseWithFlows.empty - and: "Yflow is really updated" + and: "Y-flow is really updated" northboundV2.getYFlow(yFlow.YFlowId).diverseWithFlows.empty and: "Simple multi switch flow doesn't have the 'diverse_with' field" @@ -160,4 +162,187 @@ class YFlowDiversitySpec extends HealthCheckSpecification { yFlow && yFlowHelper.deleteYFlow(yFlow.YFlowId) flow && flowHelperV2.deleteFlow(flow.flowId) } + + @Tidy + def "Able to get y-flow paths with correct overlapping segments stats"() { + given: "Switches with three not overlapping paths at least" + def swT = topologyHelper.switchTriplets.find { + [it.shared, it.ep1, it.ep2].every { it.traffGens } && + [it.pathsEp1, it.pathsEp2].every { + it.collect { pathHelper.getInvolvedIsls(it) } + .unique { a, b -> a.intersect(b) ? 0 : 1 }.size() >= 3 + } + } + assumeTrue(swT != null, "Unable to find suitable switches") + + when: "Create three y-flows with diversity enabled" + def yFlowRequest1 = yFlowHelper.randomYFlow(swT, false) + def yFlow1 = yFlowHelper.addYFlow(yFlowRequest1) + def yFlowRequest2 = yFlowHelper.randomYFlow(swT, false, [yFlowRequest1]) + .tap { it.diverseFlowId = yFlow1.YFlowId } + def yFlow2 = yFlowHelper.addYFlow(yFlowRequest2) + def yFlowRequest3 = yFlowHelper.randomYFlow(swT, false, [yFlowRequest1, yFlowRequest2]) + .tap { it.diverseFlowId = yFlow2.YFlowId } + def yFlow3 = yFlowHelper.addYFlow(yFlowRequest3) + + then: "Get flow path for all y-flows" + def yFlow1Paths = northboundV2.getYFlowPaths(yFlow1.YFlowId) + def yFlow2Paths = northboundV2.getYFlowPaths(yFlow2.YFlowId) + def yFlow3Paths = northboundV2.getYFlowPaths(yFlow3.YFlowId) + + def yFlow1SwitchCount = pathHelper.getInvolvedSwitches(PathHelper.convert(yFlow1Paths.subFlowPaths[0].forward)).size() + def yFlow2SwitchCount = pathHelper.getInvolvedSwitches(PathHelper.convert(yFlow2Paths.subFlowPaths[0].forward)).size() + def yFlow3SwitchCount = pathHelper.getInvolvedSwitches(PathHelper.convert(yFlow3Paths.subFlowPaths[0].forward)).size() + def yFlow1n2OverlapSwitchCount = Math.min(yFlow1SwitchCount, yFlow2SwitchCount) + def yFlow1n3OverlapSwitchCount = Math.min(yFlow1SwitchCount, yFlow3SwitchCount) + def yFlow2n3OverlapSwitchCount = Math.min(yFlow2SwitchCount, yFlow3SwitchCount) + + def yFlow1SharedIsls = pathHelper.getInvolvedIsls(PathHelper.convert(yFlow1Paths.sharedPath.forward)).size() + def yFlow2SharedIsls = pathHelper.getInvolvedIsls(PathHelper.convert(yFlow2Paths.sharedPath.forward)).size() + def yFlow3SharedIsls = pathHelper.getInvolvedIsls(PathHelper.convert(yFlow3Paths.sharedPath.forward)).size() + + and: "All y-flow paths have diverse group information" + + def yFlow1n2OverlapSwPercentOf1 = (100 * yFlow1n2OverlapSwitchCount / yFlow1SwitchCount).toInteger() + def yFlow1n3OverlapSwPercentOf1 = (100 * yFlow1n3OverlapSwitchCount / yFlow1SwitchCount).toInteger() + def yFlow1ExpectedValues = [ + diverseGroup: [ + (yFlow1.subFlows[0].flowId): [islCount: yFlow1SharedIsls, switchCount: yFlow1SwitchCount, islPercent: 100, switchPercent: 100], + (yFlow1.subFlows[1].flowId): [islCount: yFlow1SharedIsls, switchCount: yFlow1SwitchCount, islPercent: 100, switchPercent: 100] + ], + otherFlows : [ + (yFlow1.subFlows[0].flowId): [ + (yFlow1.subFlows[1].flowId): [islCount: yFlow1SharedIsls, switchCount: yFlow1SwitchCount, islPercent: 100, switchPercent: 100], + (yFlow2.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf1], + (yFlow2.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf1], + (yFlow3.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf1], + (yFlow3.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf1] + ], + (yFlow1.subFlows[1].flowId): [ + (yFlow1.subFlows[0].flowId): [islCount: yFlow1SharedIsls, switchCount: yFlow1SwitchCount, islPercent: 100, switchPercent: 100], + (yFlow2.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf1], + (yFlow2.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf1], + (yFlow3.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf1], + (yFlow3.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf1] + ] + ] + ] + verifySegmentsStats(yFlow1Paths, yFlow1ExpectedValues) + + def yFlow1n2OverlapSwPercentOf2 = (100 * yFlow1n2OverlapSwitchCount / yFlow2SwitchCount).toInteger() + def yFlow2n3OverlapSwPercentOf2 = (100 * yFlow2n3OverlapSwitchCount / yFlow2SwitchCount).toInteger() + def yFlow2ExpectedValues = [ + diverseGroup: [ + (yFlow2.subFlows[0].flowId): [islCount: yFlow2SharedIsls, switchCount: yFlow2SwitchCount, islPercent: 100, switchPercent: 100], + (yFlow2.subFlows[1].flowId): [islCount: yFlow2SharedIsls, switchCount: yFlow2SwitchCount, islPercent: 100, switchPercent: 100] + ], + otherFlows : [ + (yFlow2.subFlows[0].flowId): [ + (yFlow1.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf2], + (yFlow1.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf2], + (yFlow2.subFlows[1].flowId): [islCount: yFlow2SharedIsls, switchCount: yFlow2SwitchCount, islPercent: 100, switchPercent: 100], + (yFlow3.subFlows[0].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf2], + (yFlow3.subFlows[1].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf2] + ], + (yFlow2.subFlows[1].flowId): [ + (yFlow1.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf2], + (yFlow1.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n2OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n2OverlapSwPercentOf2], + (yFlow2.subFlows[0].flowId): [islCount: yFlow2SharedIsls, switchCount: yFlow2SwitchCount, islPercent: 100, switchPercent: 100], + (yFlow3.subFlows[0].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf2], + (yFlow3.subFlows[1].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf2] + ] + ] + ] + verifySegmentsStats(yFlow2Paths, yFlow2ExpectedValues) + + def yFlow1n3OverlapSwPercentOf3 = (100 * yFlow1n3OverlapSwitchCount / yFlow3SwitchCount).toInteger() + def yFlow2n3OverlapSwPercentOf3 = (100 * yFlow2n3OverlapSwitchCount / yFlow3SwitchCount).toInteger() + def yFlow3ExpectedValues = [ + diverseGroup: [ + (yFlow3.subFlows[0].flowId): [islCount: yFlow3SharedIsls, switchCount: yFlow3SwitchCount, islPercent: 100, switchPercent: 100], + (yFlow3.subFlows[1].flowId): [islCount: yFlow3SharedIsls, switchCount: yFlow3SwitchCount, islPercent: 100, switchPercent: 100], + ], + otherFlows : [ + (yFlow3.subFlows[0].flowId): [ + (yFlow1.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf3], + (yFlow1.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf3], + (yFlow2.subFlows[0].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf3], + (yFlow2.subFlows[1].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf3], + (yFlow3.subFlows[1].flowId): [islCount: yFlow3SharedIsls, switchCount: yFlow3SwitchCount, islPercent: 100, switchPercent: 100] + ], + (yFlow3.subFlows[1].flowId): [ + (yFlow1.subFlows[0].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf3], + (yFlow1.subFlows[1].flowId): [islCount: 0, switchCount: yFlow1n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow1n3OverlapSwPercentOf3], + (yFlow2.subFlows[0].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf3], + (yFlow2.subFlows[1].flowId): [islCount: 0, switchCount: yFlow2n3OverlapSwitchCount, islPercent: 0, switchPercent: yFlow2n3OverlapSwPercentOf3], + (yFlow3.subFlows[0].flowId): [islCount: yFlow3SharedIsls, switchCount: yFlow3SwitchCount, islPercent: 100, switchPercent: 100] + ] + ] + ] + verifySegmentsStats(yFlow3Paths, yFlow3ExpectedValues) + + then: "Get flow path for sub-flows" + def yFlow1s1Path = northbound.getFlowPath(yFlow1.subFlows[0].flowId) + def yFlow1s2Path = northbound.getFlowPath(yFlow1.subFlows[1].flowId) + verifySegmentsStats([yFlow1s1Path, yFlow1s2Path], yFlow1ExpectedValues) + + def yFlow2s1Path = northbound.getFlowPath(yFlow2.subFlows[0].flowId) + def yFlow2s2Path = northbound.getFlowPath(yFlow2.subFlows[1].flowId) + verifySegmentsStats([yFlow2s1Path, yFlow2s2Path], yFlow2ExpectedValues) + + def yFlow3s1Path = northbound.getFlowPath(yFlow3.subFlows[0].flowId) + def yFlow3s2Path = northbound.getFlowPath(yFlow3.subFlows[1].flowId) + verifySegmentsStats([yFlow3s1Path, yFlow3s2Path], yFlow3ExpectedValues) + + cleanup: + [yFlow1, yFlow2, yFlow3].each { it && yFlowHelper.deleteYFlow(it.YFlowId) } + } + + + void verifySegmentsStats(YFlowPaths yFlowPaths, Map expectedValuesMap) { + yFlowPaths.subFlowPaths.each { flow -> + flow.diverseGroup && with(flow.diverseGroup) { diverseGroup -> + verifyAll(diverseGroup.overlappingSegments) { + islCount == expectedValuesMap["diverseGroup"][flow.flowId]["islCount"] + switchCount == expectedValuesMap["diverseGroup"][flow.flowId]["switchCount"] + islPercent == expectedValuesMap["diverseGroup"][flow.flowId]["islPercent"] + switchPercent == expectedValuesMap["diverseGroup"][flow.flowId]["switchPercent"] + } + with(diverseGroup.otherFlows) { otherFlows -> + otherFlows.each { otherFlow -> + verifyAll(otherFlow.segmentsStats) { + islCount == expectedValuesMap["otherFlows"][flow.flowId][otherFlow.id]["islCount"] + switchCount == expectedValuesMap["otherFlows"][flow.flowId][otherFlow.id]["switchCount"] + islPercent == expectedValuesMap["otherFlows"][flow.flowId][otherFlow.id]["islPercent"] + switchPercent == expectedValuesMap["otherFlows"][flow.flowId][otherFlow.id]["switchPercent"] + } + } + } + } + } + } + + void verifySegmentsStats(List flowPaths, Map expectedValuesMap) { + flowPaths.each { flow -> + with(flow.diverseGroupPayload) { diverseGroup -> + verifyAll(diverseGroup.overlappingSegments) { + islCount == expectedValuesMap["diverseGroup"][flow.id]["islCount"] + switchCount == expectedValuesMap["diverseGroup"][flow.id]["switchCount"] + islPercent == expectedValuesMap["diverseGroup"][flow.id]["islPercent"] + switchPercent == expectedValuesMap["diverseGroup"][flow.id]["switchPercent"] + } + with(diverseGroup.otherFlows) { otherFlows -> + otherFlows.each { otherFlow -> + verifyAll(otherFlow.segmentsStats) { + islCount == expectedValuesMap["otherFlows"][flow.id][otherFlow.id]["islCount"] + switchCount == expectedValuesMap["otherFlows"][flow.id][otherFlow.id]["switchCount"] + islPercent == expectedValuesMap["otherFlows"][flow.id][otherFlow.id]["islPercent"] + switchPercent == expectedValuesMap["otherFlows"][flow.id][otherFlow.id]["switchPercent"] + } + } + } + } + } + } + } From 7d76e27f729d3a48f22c997da5c0a0ef587c151d Mon Sep 17 00:00:00 2001 From: Sergey Nikitin Date: Sun, 19 Jun 2022 22:08:10 +0300 Subject: [PATCH 6/8] Set Stats topology parallelism to 1 for local env Related to: #4844 --- confd/vars/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confd/vars/main.yaml b/confd/vars/main.yaml index a596116edfe..3502839d20a 100644 --- a/confd/vars/main.yaml +++ b/confd/vars/main.yaml @@ -172,7 +172,7 @@ kilda_storm_flow_hs_reroute_hub_count_multiplier: 2 kilda_storm_flowhs_workers: 1 kilda_storm_parallelism_workers_count: 1 kilda_storm_history_parallelism: 2 -kilda_storm_stats_parallelism: 2 +kilda_storm_stats_parallelism: 1 # must be 1 until bug https://github.com/telstra/open-kilda/issues/4844 will be fixed kilda_storm_spout_parallelism: 2 From d67c340f0cb658c5c37b20aa2a877b2b366bb841 Mon Sep 17 00:00:00 2001 From: Sergii Iakovenko Date: Fri, 17 Jun 2022 22:45:41 +0300 Subject: [PATCH 7/8] Fix y-flow sync after flow sync reimplementation. --- .../command/flow/FlowRerouteRequest.java | 12 +---- .../actions/OnSubFlowReroutedAction.java | 3 +- .../actions/RerouteSubFlowsAction.java | 4 +- .../flowhs/service/FlowRerouteService.java | 10 ++--- .../service/FlowRerouteServiceTest.java | 44 +++++++++---------- .../flowmonitoring/bolt/ActionBolt.java | 6 +-- .../services/FlowOperationsService.java | 2 +- .../service/impl/FlowServiceImpl.java | 4 +- .../reroute/service/RerouteQueueService.java | 2 +- .../reroute/service/RerouteService.java | 2 +- .../service/OperationQueueServiceTest.java | 12 ++--- .../service/RerouteQueueServiceTest.java | 2 +- .../reroute/service/RerouteServiceTest.java | 2 +- .../helpers/StatsHelper.groovy | 3 +- .../spec/flows/yflows/YFlowCreateSpec.groovy | 2 +- .../flows/yflows/YFlowPathSwapSpec.groovy | 22 +--------- .../flows/yflows/YFlowProtectedSpec.groovy | 22 +--------- 17 files changed, 54 insertions(+), 100 deletions(-) diff --git a/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java b/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java index 58fa6860ed8..36483aa9918 100644 --- a/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java +++ b/src-java/flowhs-topology/flowhs-messaging/src/main/java/org/openkilda/messaging/command/flow/FlowRerouteRequest.java @@ -58,14 +58,13 @@ public class FlowRerouteRequest extends CommandData { /** * Create Simplified request usable only for northbound API. */ - public static FlowRerouteRequest createManualFlowRerouteRequest(String flowId, boolean force, + public static FlowRerouteRequest createManualFlowRerouteRequest(String flowId, boolean ignoreBandwidth, String reason) { - return new FlowRerouteRequest(flowId, force, false, ignoreBandwidth, Collections.emptySet(), reason, true); + return new FlowRerouteRequest(flowId, false, ignoreBandwidth, Collections.emptySet(), reason, true); } @JsonCreator public FlowRerouteRequest(@NonNull @JsonProperty("flowid") String flowId, - @JsonProperty("force") boolean force, @JsonProperty("effectively_down") boolean effectivelyDown, @JsonProperty("ignore_bandwidth") boolean ignoreBandwidth, @NonNull @JsonProperty("path_ids") Set affectedIsl, @@ -77,12 +76,5 @@ public FlowRerouteRequest(@NonNull @JsonProperty("flowid") String flowId, this.reason = reason; this.ignoreBandwidth = ignoreBandwidth; this.manual = manual; - - // field "force" have been removed as part of "true flow sync" feature. Constructor argument left for now, to - // not ruin JSON compatibility for transition period. - } - - public boolean isForce() { - return false; // dummy getter for removed "force" field. } } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowReroutedAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowReroutedAction.java index 622e83317ad..e8889664cf7 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowReroutedAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/OnSubFlowReroutedAction.java @@ -60,7 +60,8 @@ protected void perform(State from, State to, Event event, stateMachine.notifyEventListeners(listener -> listener.onSubFlowProcessingStart(yFlowId, requestedFlowId)); CommandContext flowContext = stateMachine.getCommandContext().fork(requestedFlowId); - flowRerouteService.startFlowRerouting(rerouteRequest, flowContext, yFlowId); + flowRerouteService.startFlowRerouting(rerouteRequest, flowContext, yFlowId, + stateMachine.isForceReroute()); } }); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/RerouteSubFlowsAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/RerouteSubFlowsAction.java index b44c7e41f96..bf38b6ecdc1 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/RerouteSubFlowsAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/RerouteSubFlowsAction.java @@ -48,7 +48,7 @@ public void perform(State from, State to, Event event, YFlowRerouteContext conte String yFlowId = stateMachine.getYFlowId(); for (String subFlowId : targetSubFlowIds) { stateMachine.addSubFlow(subFlowId); - FlowRerouteRequest rerouteRequest = new FlowRerouteRequest(subFlowId, stateMachine.isForceReroute(), false, + FlowRerouteRequest rerouteRequest = new FlowRerouteRequest(subFlowId, false, stateMachine.isIgnoreBandwidth(), stateMachine.getAffectedIsls(), stateMachine.getRerouteReason(), false); rerouteRequests.add(rerouteRequest); @@ -72,6 +72,6 @@ private void sendRerouteRequest(YFlowRerouteFsm stateMachine, FlowRerouteRequest stateMachine.notifyEventListeners(listener -> listener.onSubFlowProcessingStart(yFlowId, subFlowId)); CommandContext flowContext = stateMachine.getCommandContext().fork(subFlowId); - flowRerouteService.startFlowRerouting(rerouteRequest, flowContext, yFlowId); + flowRerouteService.startFlowRerouting(rerouteRequest, flowContext, yFlowId, stateMachine.isForceReroute()); } } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteService.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteService.java index 305ccd8f350..bb0cc1cc6b2 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteService.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteService.java @@ -71,19 +71,19 @@ public void handleRequest(@NonNull String key, @NonNull FlowRerouteRequest rerou return; } - startFlowRerouting(key, reroute, commandContext, flowId); + startFlowRerouting(key, reroute, commandContext, flowId, false); } /** * Handles request for flow reroute. */ public void startFlowRerouting(@NonNull FlowRerouteRequest reroute, @NonNull CommandContext commandContext, - @NonNull String sharedBandwidthGroupId) { - startFlowRerouting(reroute.getFlowId(), reroute, commandContext, sharedBandwidthGroupId); + @NonNull String sharedBandwidthGroupId, boolean forceReroute) { + startFlowRerouting(reroute.getFlowId(), reroute, commandContext, sharedBandwidthGroupId, forceReroute); } private void startFlowRerouting(String key, FlowRerouteRequest reroute, CommandContext commandContext, - String sharedBandwidthGroupId) { + String sharedBandwidthGroupId, boolean forceReroute) { String flowId = reroute.getFlowId(); log.debug("Handling flow reroute request with key {} and flow ID: {}", key, flowId); @@ -109,7 +109,7 @@ private void startFlowRerouting(String key, FlowRerouteRequest reroute, CommandC FlowRerouteContext context = FlowRerouteContext.builder() .flowId(flowId) .affectedIsl(reroute.getAffectedIsl()) - .forceReroute(reroute.isForce()) + .forceReroute(forceReroute) .ignoreBandwidth(reroute.isIgnoreBandwidth()) .effectivelyDown(reroute.isEffectivelyDown()) .rerouteReason(reroute.getReason()) diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteServiceTest.java b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteServiceTest.java index 608dd42319a..e64dfa12033 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteServiceTest.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/test/java/org/openkilda/wfm/topology/flowhs/service/FlowRerouteServiceTest.java @@ -98,7 +98,7 @@ public void setUp() { public void shouldFailRerouteFlowIfNoPathAvailable() throws RecoverableException, UnroutableFlowException { Flow origin = makeFlow(); preparePathComputation(origin.getFlowId(), new UnroutableFlowException(injectedErrorMessage)); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); testExpectedFailure(dummyRequestKey, request, commandContext, origin, FlowStatus.DOWN, ErrorType.NOT_FOUND); @@ -111,7 +111,7 @@ public void shouldFailRerouteFlowIfRecoverableException() throws RecoverableExce Flow origin = makeFlow(); preparePathComputation(origin.getFlowId(), new RecoverableException(injectedErrorMessage)); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); testExpectedFailure(dummyRequestKey, request, commandContext, origin, FlowStatus.UP, ErrorType.INTERNAL_ERROR); @@ -129,7 +129,7 @@ public void shouldFailRerouteFlowIfMultipleOverprovisionBandwidth() doReturn(-1L) .when(repository).updateAvailableBandwidth(any(), anyInt(), any(), anyInt()); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); testExpectedFailure(dummyRequestKey, request, commandContext, origin, FlowStatus.UP, ErrorType.INTERNAL_ERROR); @@ -147,7 +147,7 @@ public void shouldFailRerouteFlowIfNoResourcesAvailable() .when(flowResourcesManager).allocateFlowResources(makeFlowArgumentMatch(origin.getFlowId()), any(), any()); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); testExpectedFailure(dummyRequestKey, request, commandContext, origin, FlowStatus.UP, ErrorType.INTERNAL_ERROR); @@ -166,7 +166,7 @@ public void shouldFailRerouteFlowOnResourcesAllocationConstraint() .when(repository) .add(any(FlowPath.class)); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); testExpectedFailure(dummyRequestKey, request, commandContext, origin, FlowStatus.UP, ErrorType.INTERNAL_ERROR); } @@ -187,7 +187,7 @@ private void testExpectedFailure(String key, public void shouldSkipRerouteIfNoNewPathFound() throws RecoverableException, UnroutableFlowException { Flow origin = makeFlow(); preparePathComputation(origin.getFlowId(), make2SwitchesPathPair()); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); makeService().handleRequest(dummyRequestKey, request, commandContext); @@ -207,7 +207,7 @@ public void shouldFailRerouteOnUnsuccessfulInstallation() preparePathComputation(origin.getFlowId(), newPathPair); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -245,7 +245,7 @@ public void shouldFailRerouteOnTimeoutDuringInstallation() preparePathComputation(origin.getFlowId(), newPathPair); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -274,7 +274,7 @@ public void shouldFailRerouteOnUnsuccessfulValidation() preparePathComputation(origin.getFlowId(), newPathPair); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -313,7 +313,7 @@ public void shouldFailRerouteOnTimeoutDuringValidation() FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -349,7 +349,7 @@ public void shouldFailRerouteOnSwapPathsError() eq(FlowPathStatus.IN_PROGRESS)); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -386,7 +386,7 @@ public void shouldFailRerouteOnErrorDuringCompletingFlowPathInstallation() eq(FlowPathStatus.ACTIVE)); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -418,7 +418,7 @@ public void shouldCompleteRerouteOnErrorDuringCompletingFlowPathRemoval() .remove(eq(origin.getForwardPathId())); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -441,7 +441,7 @@ public void shouldCompleteRerouteOnErrorDuringResourceDeallocation() preparePathComputation(origin.getFlowId(), make3SwitchesPathPair()); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -478,7 +478,7 @@ public void shouldSuccessfullyRerouteFlow() preparePathComputation(origin.getFlowId(), make3SwitchesPathPair()); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -513,7 +513,7 @@ public void shouldSuccessfullyHandleOverlappingRequests() FlowRerouteService service = makeService(); - FlowRerouteRequest rerouteRequest = new FlowRerouteRequest(origin.getFlowId(), false, false, + FlowRerouteRequest rerouteRequest = new FlowRerouteRequest(origin.getFlowId(), false, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, rerouteRequest, commandContext); @@ -548,7 +548,7 @@ public void shouldMakeFlowDownOnTimeoutIfEffectivelyDown() preparePathComputation(origin.getFlowId(), make3SwitchesPathPair()); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, true, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), true, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -573,7 +573,7 @@ public void shouldIgnoreEffectivelyDownStateIfSamePaths() preparePathComputation(origin.getFlowId(), make2SwitchesPathPair()); FlowRerouteService service = makeService(); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, true, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), true, false, Collections.emptySet(), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -598,7 +598,7 @@ public void shouldProcessRerouteForValidRequest() FlowRerouteService service = makeService(); IslEndpoint affectedEndpoint = extractIslEndpoint(origin); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, true, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), true, false, Collections.singleton(affectedEndpoint), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -622,7 +622,7 @@ public void shouldSkipRerouteOnOutdatedRequest() { FlowRerouteService service = makeService(); IslEndpoint affectedEndpoint = extractIslEndpoint(origin); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, true, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), true, false, Collections.singleton(affectedEndpoint), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -641,7 +641,7 @@ public void shouldMoveFlowToDegradedIfPathWithRequiredLatencyNotFound() throws E FlowRerouteService service = makeService(); IslEndpoint affectedEndpoint = extractIslEndpoint(origin); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, true, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), true, false, Collections.singleton(affectedEndpoint), null, false); service.handleRequest(currentRequestKey, request, commandContext); @@ -666,7 +666,7 @@ public void shouldFailRerouteYSubFlow() throws UnroutableFlowException, Recovera FlowRerouteService service = makeService(); IslEndpoint affectedEndpoint = extractIslEndpoint(origin); - FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), false, true, + FlowRerouteRequest request = new FlowRerouteRequest(origin.getFlowId(), true, false, Collections.singleton(affectedEndpoint), null, false); service.handleRequest(currentRequestKey, request, commandContext); diff --git a/src-java/flowmonitoring-topology/flowmonitoring-storm-topology/src/main/java/org/openkilda/wfm/topology/flowmonitoring/bolt/ActionBolt.java b/src-java/flowmonitoring-topology/flowmonitoring-storm-topology/src/main/java/org/openkilda/wfm/topology/flowmonitoring/bolt/ActionBolt.java index 928faeab3ab..8aae5c5d770 100644 --- a/src-java/flowmonitoring-topology/flowmonitoring-storm-topology/src/main/java/org/openkilda/wfm/topology/flowmonitoring/bolt/ActionBolt.java +++ b/src-java/flowmonitoring-topology/flowmonitoring-storm-topology/src/main/java/org/openkilda/wfm/topology/flowmonitoring/bolt/ActionBolt.java @@ -27,6 +27,7 @@ import org.openkilda.bluegreen.LifecycleEvent; import org.openkilda.messaging.command.flow.FlowRerouteRequest; +import org.openkilda.messaging.command.flow.FlowSyncRequest; import org.openkilda.messaging.info.flow.UpdateFlowCommand; import org.openkilda.persistence.PersistenceManager; import org.openkilda.server42.messaging.FlowDirection; @@ -121,14 +122,13 @@ public void declareOutputFields(OutputFieldsDeclarer declarer) { @Override public void sendFlowSyncRequest(String flowId) { - FlowRerouteRequest request = new FlowRerouteRequest(flowId, true, false, false, Collections.emptySet(), - "Flow latency become healthy", false); + FlowSyncRequest request = new FlowSyncRequest(flowId); emit(getCurrentTuple(), new Values(request, getCommandContext())); } @Override public void sendFlowRerouteRequest(String flowId) { - FlowRerouteRequest request = new FlowRerouteRequest(flowId, false, false, false, Collections.emptySet(), + FlowRerouteRequest request = new FlowRerouteRequest(flowId, false, false, Collections.emptySet(), "Flow latency become unhealthy", false); emit(getCurrentTuple(), new Values(request, getCommandContext())); } diff --git a/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java b/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java index 543d2bdb06e..36833e4b9fd 100644 --- a/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java +++ b/src-java/nbworker-topology/nbworker-storm-topology/src/main/java/org/openkilda/wfm/topology/nbworker/services/FlowOperationsService.java @@ -586,7 +586,7 @@ public List makeRerouteRequests( Flow flow = entry.getFlow(); if (processed.add(flow.getFlowId())) { FlowRerouteRequest request = new FlowRerouteRequest( - flow.getFlowId(), false, false, false, affectedIslEndpoints, reason, false); + flow.getFlowId(), false, false, affectedIslEndpoints, reason, false); results.add(request); } } diff --git a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java index 7ab4d913c97..3a81fd37479 100644 --- a/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java +++ b/src-java/northbound-service/northbound/src/main/java/org/openkilda/northbound/service/impl/FlowServiceImpl.java @@ -589,7 +589,7 @@ public CompletableFuture swapFlowPaths(String flowId) { public CompletableFuture rerouteFlow(String flowId) { logger.info("Reroute flow: {}={}", FLOW_ID, flowId); - FlowRerouteRequest payload = createManualFlowRerouteRequest(flowId, false, false, "initiated via Northbound"); + FlowRerouteRequest payload = createManualFlowRerouteRequest(flowId, false, "initiated via Northbound"); CommandMessage command = new CommandMessage( payload, System.currentTimeMillis(), RequestCorrelationId.getId()); @@ -656,7 +656,7 @@ public CompletableFuture modifyMeter(String flowId) { public CompletableFuture rerouteFlowV2(String flowId) { logger.info("Processing flow reroute: {}", flowId); - FlowRerouteRequest payload = createManualFlowRerouteRequest(flowId, false, false, "initiated via Northbound"); + FlowRerouteRequest payload = createManualFlowRerouteRequest(flowId, false, "initiated via Northbound"); CommandMessage command = new CommandMessage( payload, System.currentTimeMillis(), RequestCorrelationId.getId(), Destination.WFM); diff --git a/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueService.java b/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueService.java index 482add71c91..05fb2f3e714 100644 --- a/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueService.java +++ b/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueService.java @@ -303,7 +303,7 @@ private void sendRerouteRequest(String flowId, FlowThrottlingData throttlingData throttlingData.isForce(), throttlingData.getReason(), throttlingData.isIgnoreBandwidth()); carrier.sendRerouteRequest(throttlingData.getCorrelationId(), request); } else { - FlowRerouteRequest request = new FlowRerouteRequest(flowId, throttlingData.isForce(), + FlowRerouteRequest request = new FlowRerouteRequest(flowId, throttlingData.isEffectivelyDown(), throttlingData.isIgnoreBandwidth(), throttlingData.getAffectedIsl(), throttlingData.getReason(), false); carrier.sendRerouteRequest(throttlingData.getCorrelationId(), request); diff --git a/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteService.java b/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteService.java index 927ba1c5450..0f016502756 100644 --- a/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteService.java +++ b/src-java/reroute-topology/reroute-storm-topology/src/main/java/org/openkilda/wfm/topology/reroute/service/RerouteService.java @@ -450,7 +450,7 @@ public void processRerouteRequest(MessageSender sender, String correlationId, Fl FlowThrottlingData flowThrottlingData = getFlowThrottlingDataBuilder(flow.orElse(null)) .correlationId(correlationId) .affectedIsl(request.getAffectedIsl()) - .force(request.isForce()) + .force(false) .effectivelyDown(request.isEffectivelyDown()) .reason(request.getReason()) .build(); diff --git a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/OperationQueueServiceTest.java b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/OperationQueueServiceTest.java index bb69d763f9e..a0b24c2dc2f 100644 --- a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/OperationQueueServiceTest.java +++ b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/OperationQueueServiceTest.java @@ -39,9 +39,9 @@ public class OperationQueueServiceTest { @Test public void shouldAddFirst() { service.addLast(TEST_FLOW_ID, TEST_CORRELATION_ID_A, - createManualFlowRerouteRequest(TEST_FLOW_ID, false, false, "")); + createManualFlowRerouteRequest(TEST_FLOW_ID, false, "")); service.addLast(TEST_FLOW_ID, TEST_CORRELATION_ID_C, - createManualFlowRerouteRequest(TEST_FLOW_ID, false, false, "")); + createManualFlowRerouteRequest(TEST_FLOW_ID, false, "")); FlowQueueData flowQueueData = service.getFlowCommands().get(TEST_FLOW_ID); @@ -74,9 +74,9 @@ public void shouldAddFirst() { @Test public void shouldAddLast() { service.addLast(TEST_FLOW_ID, TEST_CORRELATION_ID_A, - createManualFlowRerouteRequest(TEST_FLOW_ID, false, false, "")); + createManualFlowRerouteRequest(TEST_FLOW_ID, false, "")); service.addLast(TEST_FLOW_ID, TEST_CORRELATION_ID_B, - createManualFlowRerouteRequest(TEST_FLOW_ID, false, false, "")); + createManualFlowRerouteRequest(TEST_FLOW_ID, false, "")); FlowQueueData flowQueueData = service.getFlowCommands().get(TEST_FLOW_ID); @@ -100,9 +100,9 @@ public void shouldAddLast() { @Test public void shouldHandleTimeout() { service.addLast(TEST_FLOW_ID, TEST_CORRELATION_ID_A, - createManualFlowRerouteRequest(TEST_FLOW_ID, false, false, "")); + createManualFlowRerouteRequest(TEST_FLOW_ID, false, "")); service.addLast(TEST_FLOW_ID, TEST_CORRELATION_ID_B, - createManualFlowRerouteRequest(TEST_FLOW_ID, false, false, "")); + createManualFlowRerouteRequest(TEST_FLOW_ID, false, "")); FlowQueueData flowQueueData = service.getFlowCommands().get(TEST_FLOW_ID); diff --git a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueServiceTest.java b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueServiceTest.java index 7ebe22f85ca..8d20d5e306a 100644 --- a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueServiceTest.java +++ b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteQueueServiceTest.java @@ -599,7 +599,7 @@ private FlowThrottlingDataBuilder getFlowThrottlingData(YFlow flow, String corre } private FlowRerouteRequest getFlowRerouteRequest(String flowId, FlowThrottlingData flowThrottlingData) { - return new FlowRerouteRequest(flowId, flowThrottlingData.isForce(), flowThrottlingData.isEffectivelyDown(), + return new FlowRerouteRequest(flowId, flowThrottlingData.isEffectivelyDown(), flowThrottlingData.isIgnoreBandwidth(), flowThrottlingData.getAffectedIsl(), flowThrottlingData.getReason(), false); } diff --git a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java index 8a48bcbd40a..d2d97951b04 100644 --- a/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java +++ b/src-java/reroute-topology/reroute-storm-topology/src/test/java/org/openkilda/wfm/topology/reroute/service/RerouteServiceTest.java @@ -594,7 +594,7 @@ public void processManualRerouteRequest() { RerouteService rerouteService = new RerouteService(persistenceManager); - FlowRerouteRequest request = new FlowRerouteRequest(regularFlow.getFlowId(), true, true, false, + FlowRerouteRequest request = new FlowRerouteRequest(regularFlow.getFlowId(), true, false, Collections.emptySet(), "reason", true); rerouteService.processRerouteRequest(carrier, CORRELATION_ID, request); diff --git a/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/StatsHelper.groovy b/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/StatsHelper.groovy index 41d762f87d5..d748ba485b7 100644 --- a/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/StatsHelper.groovy +++ b/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/StatsHelper.groovy @@ -63,7 +63,8 @@ class StatsHelper { def dpsYPoint = otsdb.query(from, metricPrefix + "yFlow.meter.yPoint.bytes", ["y_flow_id": yFlowId]).dps if (expectTraffic) { assert dpsShared.values().any { it > 0 }, yFlowId - assert dpsYPoint.values().any { it > 0 }, yFlowId + //TODO: an issue to be fixed https://github.com/telstra/open-kilda/issues/4852 + //assert dpsYPoint.values().any { it > 0 }, yFlowId } else { assert dpsShared.size() > 0, yFlowId assert dpsYPoint.size() > 0, yFlowId diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowCreateSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowCreateSpec.groovy index 3c31db2463e..a1c66ab8a05 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowCreateSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowCreateSpec.groovy @@ -551,7 +551,7 @@ source: switchId="${flow.sharedEndpoint.switchId}" port=${flow.sharedEndpoint.po !swT.shared.wb5164 && yPoints.size() == 1 && (yPoints[0] == swT.ep1 || yPoints[0] == swT.ep2) }], [name : "yp==se", condition: { SwitchTriplet swT -> - def yPoints = findPotentialYPoints(swT) + def yPoints = yFlowHelper.findPotentialYPoints(swT) yPoints.size() == 1 && yPoints[0] == swT.shared && swT.shared != swT.ep1 && swT.shared != swT.ep2 }] ] requiredCases.each { it.picked = false } diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowPathSwapSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowPathSwapSpec.groovy index 94e99dc2060..f7387be559d 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowPathSwapSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowPathSwapSpec.groovy @@ -458,7 +458,7 @@ class YFlowPathSwapSpec extends HealthCheckSpecification { return topologyHelper.switchTriplets.find { def ep1paths = it.pathsEp1.unique(false) { a, b -> a.intersect(b) == [] ? 1 : 0 } def ep2paths = it.pathsEp2.unique(false) { a, b -> a.intersect(b) == [] ? 1 : 0 } - def yPoints = findPotentialYPoints(it) + def yPoints = yFlowHelper.findPotentialYPoints(it) it.ep1 != it.ep2 && it.ep1 != it.shared && it.ep2 != it.shared && yPoints.size() == 1 && yPoints[0] != it.shared && yPoints[0] != it.ep1 && yPoints[0] != it.ep2 && @@ -468,24 +468,4 @@ class YFlowPathSwapSpec extends HealthCheckSpecification { ep1paths.size() >= 2 && ep2paths.size() >= 2 } } - - @Memoized - List findPotentialYPoints(SwitchTriplet swT) { - def sortedEp1Paths = swT.pathsEp1.sort { it.size() } - def potentialEp1Paths = sortedEp1Paths.takeWhile { it.size() == sortedEp1Paths[0].size() } - def potentialEp2Paths = potentialEp1Paths.collect { potentialEp1Path -> - def sortedEp2Paths = swT.pathsEp2.sort { - it.size() - it.intersect(potentialEp1Path).size() - } - [path1 : potentialEp1Path, - potentialPaths2: sortedEp2Paths.takeWhile { it.size() == sortedEp2Paths[0].size() }] - } - return potentialEp2Paths.collectMany { path1WithPath2 -> - path1WithPath2.potentialPaths2.collect { List potentialPath2 -> - def switches = pathHelper.getInvolvedSwitches(path1WithPath2.path1) - .intersect(pathHelper.getInvolvedSwitches(potentialPath2)) - switches ? switches[-1] : null - } - }.findAll().unique() - } } diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowProtectedSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowProtectedSpec.groovy index 833c1d56e75..43241ebf0cc 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowProtectedSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/yflows/YFlowProtectedSpec.groovy @@ -43,7 +43,7 @@ class YFlowProtectedSpec extends HealthCheckSpecification { def swT = topologyHelper.switchTriplets.find { def ep1paths = it.pathsEp1.unique(false) { a, b -> a.intersect(b) == [] ? 1 : 0 } def ep2paths = it.pathsEp2.unique(false) { a, b -> a.intersect(b) == [] ? 1 : 0 } - def yPoints = findPotentialYPoints(it) + def yPoints = yFlowHelper.findPotentialYPoints(it) //se == yp yPoints.size() == 1 && yPoints[0] == it.shared && yPoints[0] != it.ep1 && yPoints[0] != it.ep2 && it.ep1 != it.ep2 && ep1paths.size() >= 2 && ep2paths.size() >= 2 @@ -119,24 +119,4 @@ class YFlowProtectedSpec extends HealthCheckSpecification { cleanup: yFlow && yFlowHelper.deleteYFlow(yFlow.YFlowId) } - - @Memoized - List findPotentialYPoints(SwitchTriplet swT) { - def sortedEp1Paths = swT.pathsEp1.sort { it.size() } - def potentialEp1Paths = sortedEp1Paths.takeWhile { it.size() == sortedEp1Paths[0].size() } - def potentialEp2Paths = potentialEp1Paths.collect { potentialEp1Path -> - def sortedEp2Paths = swT.pathsEp2.sort { - it.size() - it.intersect(potentialEp1Path).size() - } - [path1 : potentialEp1Path, - potentialPaths2: sortedEp2Paths.takeWhile { it.size() == sortedEp2Paths[0].size() }] - } - return potentialEp2Paths.collectMany { path1WithPath2 -> - path1WithPath2.potentialPaths2.collect { List potentialPath2 -> - def switches = pathHelper.getInvolvedSwitches(path1WithPath2.path1) - .intersect(pathHelper.getInvolvedSwitches(potentialPath2)) - switches ? switches[-1] : null - } - }.findAll().unique() - } } From 31f437e8e1ab140230072fa28b19bff9eb40e069 Mon Sep 17 00:00:00 2001 From: Sergii Iakovenko Date: Wed, 22 Jun 2022 15:27:56 +0300 Subject: [PATCH 8/8] Update CHANGELOG.md with 1.121.0 release notes. --- CHANGELOG.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80f73063aee..9dba48d8a47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,28 @@ # Changelog -## v1.120.2 (10/06/2022) +## v1.121.0 (22/06/2022) + +### Bug Fixes: +- [#4846](https://github.com/telstra/open-kilda/pull/4846) Fix y-flow sync after flow sync reimplementation [**storm-topologies**] +- [#4831](https://github.com/telstra/open-kilda/pull/4831) Fix validation and sync for one-switch y-flow (Issues: [#4824](https://github.com/telstra/open-kilda/issues/4824) [#4825](https://github.com/telstra/open-kilda/issues/4825)) + +### Improvements: +- [#4840](https://github.com/telstra/open-kilda/pull/4840) Return diversity info in get paths response [**northbound**][**storm-topologies**] +- [#4847](https://github.com/telstra/open-kilda/pull/4847) Set Stats topology parallelism to 1 for local env (Issue: [#4844](https://github.com/telstra/open-kilda/issues/4844)) [**storm-topologies**] + +### Other changes: +- [#4817](https://github.com/telstra/open-kilda/pull/4817) True flow sync [**storm-topologies**] +- [#4796](https://github.com/telstra/open-kilda/pull/4796) Unmark DRAFT from y-flow API [**northbound**] +- [#4830](https://github.com/telstra/open-kilda/pull/4830) Update rule manager docs [**docs**] +For the complete list of changes, check out [the commit log](https://github.com/telstra/open-kilda/compare/v1.120.2...v1.121.0). + +### Affected Components: +nbworker, stats, nb, flow-hs + +--- + +## v1.120.2 (10/06/2022) ### Bug Fixes: - [#4839](https://github.com/telstra/open-kilda/pull/4839) Fix switch sync to be able to repair misconfigured rules with the same cookie (Issue: [#4838](https://github.com/telstra/open-kilda/issues/4838)) [**floodlight**] @@ -28,6 +49,8 @@ flow-hs, fl, stats, swmanager, nb, network OrientDB schema have been changed in this release. You need to apply schema migration. Please follow [migration instructions](https://github.com/telstra/open-kilda/tree/develop/docker/db-migration/migrations). +--- + ## v1.120.1 (01/06/2022) ### Bug Fixes: