From: Joakim Törnqvist Date: Wed, 17 Jan 2024 14:35:53 +0000 (+0000) Subject: Refactoring rollback when service create fails X-Git-Tag: 9.0.0~42^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=transportpce.git;a=commitdiff_plain;h=9a30b4a275893473efc7486a24605aeb9c11d9f8 Refactoring rollback when service create fails The new rollback feature is primarily implemented in the method deviceRendering in the class RendererServiceOperationsImpl. The new class TransactionHistory is passed into DeviceRendererServiceImpl via DeviceRenderingTask. DeviceRendererServiceImpl populates the TransationHistory class with created interfaces etc. A new rollback task NetworkDeviceRenderingRollbackTask has been created intended to replace DeviceRenderingRollbackTask. The class is instantiated with a TransactionHistory object intended to be used in case of a rollback. Sample pseudo code extract class RendererServiceOperationsImpl: private List deviceRendering(...) { History transactionHistory = new TransactionHistory(); ListenableFuture atozrenderingFuture = this.executor.submit( new DeviceRenderingTask(..., transactionHistory)); ListenableFuture ztoarenderingFuture = this.executor.submit( new DeviceRenderingTask(..., transactionHistory)); ListenableFuture> renderingCombinedFuture = Futures.allAsList( atozrenderingFuture, ztoarenderingFuture ); List renderingResults = new ArrayList<>(2); renderingResults = renderingCombinedFuture.get(...); rollbackProcessor.addTask( new NetworkDeviceRenderingRollbackTask( "RollbackTransactionHistoryTask", transactionHistory, ! (renderingResults.get(0).isSuccess() && renderingResults.get(1).isSuccess()), deviceRenderer, new RollbackResultMessage() ) ); return renderingResults; } New somewhat simplified rollback method using TransactionHistory intended to replace the previous method using RendererRollbackInput: class RendererServiceOperationsImpl: @Override public RendererRollbackOutput rendererRollback( History transactionHistory ) { LOG.info("Rolling back..."); Result rollbackResult = new FailedRollbackResult(); Subscriber deleteSubscriber = new DeleteSubscriber(rollbackResult); transactionHistory.rollback( new DeleteService( crossConnect, openRoadmInterfaces, deleteSubscriber ) ); LOG.info("Rollback done!"); return rollbackResult.renderRollbackOutput(); } JIRA: TRNSPRTPCE-615 Change-Id: Ib795f077ae763bd92bac44ee77186a19ed0e4b2a Signed-off-by: Joakim Törnqvist --- diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererService.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererService.java index a242147bd..049247b45 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererService.java +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererService.java @@ -10,6 +10,7 @@ package org.opendaylight.transportpce.renderer.provisiondevice; import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException; import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.History; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.CreateOtsOmsInput; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.CreateOtsOmsOutput; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackInput; @@ -44,6 +45,35 @@ public interface DeviceRendererService { */ ServicePathOutput setupServicePath(ServicePathInput input, ServicePathDirection direction); + /** + * This method set's wavelength path based on following steps. + * + *

+ * For each node: + * 1. Create Och interface on source termination point. + * 2. Create Och interface on destination termination point. + * 3. Create cross connect between source and destination tps created in step 1 + * and 2. + * + * Naming convention used for OCH interfaces name : tp-wavenumber Naming + * convention used for cross connect name : src-dest-wavenumber + *

+ * + * @param input + * Input parameter from the service-path yang model + * @param direction + * Service Path direction + * @param transactionHistory + * Object tracking created interface(s) and connection(s). + * + * @return Result list of all nodes if request successful otherwise specific + * reason of failure. + */ + ServicePathOutput setupServicePath( + ServicePathInput input, + ServicePathDirection direction, + History transactionHistory); + /** * This method removes wavelength path based on following steps. * @@ -72,6 +102,14 @@ public interface DeviceRendererService { */ RendererRollbackOutput rendererRollback(RendererRollbackInput input); + /** + * Rollback created interfaces and cross connects specified by transaction history. + * + * @param transactionHistory The transaction history in need of rollback. + * @return Success flag and nodes which failed to rollback + */ + RendererRollbackOutput rendererRollback(History transactionHistory); + /** * This method creates the basis of ots and oms interfaces on a specific ROADM degree. * diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererServiceImpl.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererServiceImpl.java index 2ffa8be25..7c204f255 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererServiceImpl.java +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/DeviceRendererServiceImpl.java @@ -49,6 +49,15 @@ import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfa import org.opendaylight.transportpce.renderer.openroadminterface.OpenRoadmInterfaceFactory; import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServiceListTopology; import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.Connection; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.DeviceInterface; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.DeleteService; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.DeleteSubscriber; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.FailedRollbackResult; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Result; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Subscriber; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.History; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.NonStickHistoryMemory; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.ServiceNodelist; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.service.nodelist.NodelistBuilder; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.service.nodelist.NodelistKey; @@ -113,12 +122,21 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { this.openRoadmInterfaceFactory = new OpenRoadmInterfaceFactory(mappingUtils, portMapping, openRoadmInterfaces); } + @Override + public ServicePathOutput setupServicePath(ServicePathInput input, ServicePathDirection direction) { + return setupServicePath(input, direction, new NonStickHistoryMemory()); + } + @SuppressWarnings("rawtypes") // FIXME check if the ForkJoinTask raw type can be avoided // Raw types use are discouraged since they lack type safety. // Resulting Problems are observed at run time and not at compile time @Override - public ServicePathOutput setupServicePath(ServicePathInput input, ServicePathDirection direction) { + public ServicePathOutput setupServicePath( + ServicePathInput input, + ServicePathDirection direction, + History transactionHistory + ) { LOG.info("setup service path for input {} and direction {}", input, direction); List nodes = new ArrayList<>(); if (input.getNodes() != null) { @@ -164,10 +182,14 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { crossConnectFlag++; String supportingOchInterface = this.openRoadmInterfaceFactory.createOpenRoadmOchInterface( nodeId, destTp, spectrumInformation); + transactionHistory.add(new DeviceInterface(nodeId, supportingOchInterface)); + // Split the string based on # pass the last element as the supported Interface // This is needed for 7.1 device models with B100G, we have OTSI, OTSI-group combined as OCH String[] listOfSuppOchInf = supportingOchInterface.split("#"); List createdOchInf = Arrays.asList(listOfSuppOchInf); + transactionHistory.addInterfaces(nodeId, listOfSuppOchInf); + createdOchInterfaces.addAll(createdOchInf); LOG.info("DEST all otsi interfaces {}", createdOchInterfaces); // Taking the last element @@ -176,6 +198,8 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { .createOpenRoadmOtu4Interface(nodeId, destTp, supportingOchInterface, apiInfoA, apiInfoZ); createdOtuInterfaces.add(supportingOtuInterface); + transactionHistory.add(new DeviceInterface(nodeId, supportingOtuInterface)); + LOG.info("all dest otu interfaces {}", createdOtuInterfaces); if (srcTp == null) { otnLinkTps.add(new LinkTpBuilder().setNodeId(nodeId).setTpId(destTp).build()); @@ -183,23 +207,32 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { // If src and dest tp contains the network token, then it is regenerator LOG.info("Create the ODUCn for regen on the dest-tp"); // Here we first create ODUCn interface for the Regen - createdOduInterfaces.add(this.openRoadmInterfaceFactory - .createOpenRoadmOducn(nodeId, destTp)); + String openRoadmOducn = this.openRoadmInterfaceFactory + .createOpenRoadmOducn(nodeId, destTp); + createdOduInterfaces.add(openRoadmOducn); + transactionHistory.addInterfaces(nodeId, openRoadmOducn); + LOG.info("all dest odu interfaces {}", createdOduInterfaces); } else { // This is needed for 7.1 device models for 400GE, since we have ODUC4 and ODUflex // are combined - createdOduInterfaces = Set.of(this.openRoadmInterfaceFactory - .createOpenRoadmOdu4HOInterface( - nodeId, destTp, false, apiInfoA, apiInfoZ, PT_07).split("#")); + String[] oduInterfaces = this.openRoadmInterfaceFactory + .createOpenRoadmOdu4HOInterface( + nodeId, destTp, false, apiInfoA, apiInfoZ, PT_07).split("#"); + createdOduInterfaces.addAll(Arrays.asList(oduInterfaces)); + transactionHistory.addInterfaces(nodeId, oduInterfaces); + } } if ((srcTp != null) && srcTp.contains(StringConstants.CLIENT_TOKEN)) { LOG.info("Adding supporting EThernet interface for node {}, src tp {}", nodeId, srcTp); crossConnectFlag++; // create OpenRoadm Xponder Client Interfaces - createdEthInterfaces.add(this.openRoadmInterfaceFactory.createOpenRoadmEthInterface( - nodeId, srcTp)); + String openRoadmEthInterface = this.openRoadmInterfaceFactory.createOpenRoadmEthInterface( + nodeId, srcTp); + createdEthInterfaces.add(openRoadmEthInterface); + transactionHistory.add(new DeviceInterface(nodeId, openRoadmEthInterface)); + } if ((srcTp != null) && srcTp.contains(StringConstants.NETWORK_TOKEN)) { LOG.info("Adding supporting OCH interface for node {}, src tp {}, spectrumInformation {}", @@ -208,10 +241,14 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { // create OpenRoadm Xponder Line Interfaces String supportingOchInterface = this.openRoadmInterfaceFactory.createOpenRoadmOchInterface( nodeId, srcTp, spectrumInformation); + transactionHistory.add(new DeviceInterface(nodeId, supportingOchInterface)); + // createdOchInterfaces.add(supportingOchInterface); // Split the string based on # pass the last element as the supported Interface // This is needed for 7.1 device models with B100G, we have OTSI, OTSI-group combined as OCH String[] listOfSuppOchInf = supportingOchInterface.split("#"); + transactionHistory.addInterfaces(nodeId, listOfSuppOchInf); + List tmpCreatedOchInterfaces = Arrays.asList(listOfSuppOchInf); createdOchInterfaces.addAll(tmpCreatedOchInterfaces); // Taking the last element @@ -219,40 +256,53 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { String supportingOtuInterface = this.openRoadmInterfaceFactory.createOpenRoadmOtu4Interface( nodeId, srcTp, supportingOchInterface, apiInfoA, apiInfoZ); createdOtuInterfaces.add(supportingOtuInterface); + transactionHistory.add(new DeviceInterface(nodeId, supportingOtuInterface)); + if (destTp == null) { otnLinkTps.add(new LinkTpBuilder().setNodeId(nodeId).setTpId(srcTp).build()); } else if (destTp.contains(StringConstants.NETWORK_TOKEN)) { // If the src and dest tp have network-token, then it is a regen LOG.info("Create the regen-interfaces on the src-tp"); // Here we first create ODUCn interface for the Regen - createdOduInterfaces.add(this.openRoadmInterfaceFactory.createOpenRoadmOducn(nodeId, - srcTp)); + String openRoadmOducn = this.openRoadmInterfaceFactory.createOpenRoadmOducn(nodeId, + srcTp); + createdOduInterfaces.add(openRoadmOducn); + transactionHistory.add(new DeviceInterface(nodeId, openRoadmOducn)); + LOG.info("all src odu interfaces {}", createdOduInterfaces); } else { - createdOduInterfaces.add(this.openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface( - nodeId, srcTp, false, apiInfoA, apiInfoZ, PT_07)); + String openRoadmOdu4HOInterface = this.openRoadmInterfaceFactory + .createOpenRoadmOdu4HOInterface(nodeId, srcTp, false, apiInfoA, apiInfoZ, PT_07); + createdOduInterfaces.add(openRoadmOdu4HOInterface); + transactionHistory.add(new DeviceInterface(nodeId, openRoadmOdu4HOInterface)); } } if ((destTp != null) && destTp.contains(StringConstants.CLIENT_TOKEN)) { LOG.info("Adding supporting EThernet interface for node {}, dest tp {}", nodeId, destTp); crossConnectFlag++; // create OpenRoadm Xponder Client Interfaces - createdEthInterfaces.add(this.openRoadmInterfaceFactory.createOpenRoadmEthInterface( - nodeId, destTp)); + String openRoadmEthInterface = this.openRoadmInterfaceFactory.createOpenRoadmEthInterface( + nodeId, destTp); + createdEthInterfaces.add(openRoadmEthInterface); + transactionHistory.add(new DeviceInterface(nodeId, openRoadmEthInterface)); } if ((srcTp != null) && (srcTp.contains(StringConstants.TTP_TOKEN) || srcTp.contains(StringConstants.PP_TOKEN))) { LOG.info("Adding supporting OCH interface for node {}, src tp {}, spectrumInformation {}", nodeId, srcTp, spectrumInformation); - createdOchInterfaces.addAll(this.openRoadmInterfaceFactory.createOpenRoadmOchInterfaces( - nodeId, srcTp, spectrumInformation)); + List openRoadmOchInterfaces = this.openRoadmInterfaceFactory + .createOpenRoadmOchInterfaces(nodeId, srcTp, spectrumInformation); + createdOchInterfaces.addAll(openRoadmOchInterfaces); + transactionHistory.addInterfaces(nodeId, openRoadmOchInterfaces); } if ((destTp != null) && (destTp.contains(StringConstants.TTP_TOKEN) || destTp.contains(StringConstants.PP_TOKEN))) { LOG.info("Adding supporting OCH interface for node {}, dest tp {}, spectrumInformation {}", nodeId, destTp, spectrumInformation); - createdOchInterfaces.addAll(this.openRoadmInterfaceFactory.createOpenRoadmOchInterfaces( - nodeId, destTp, spectrumInformation)); + List openRoadmOchInterfaces = this.openRoadmInterfaceFactory + .createOpenRoadmOchInterfaces(nodeId, destTp, spectrumInformation); + createdOchInterfaces.addAll(openRoadmOchInterfaces); + transactionHistory.addInterfaces(nodeId, openRoadmOchInterfaces); } if (crossConnectFlag < 1) { LOG.info("Creating cross connect between source {} and destination {} for node {}", srcTp, @@ -261,7 +311,9 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { this.crossConnect.postCrossConnect(nodeId, srcTp, destTp, spectrumInformation); if (connectionNameOpt.isPresent()) { nodesProvisioned.add(nodeId); - createdConnections.add(connectionNameOpt.orElseThrow()); + String connectionName = connectionNameOpt.orElseThrow(); + createdConnections.add(connectionName); + transactionHistory.add(new Connection(nodeId, connectionName, false)); } else { processErrorMessage("Unable to post Roadm-connection for node " + nodeId, forkJoinPool, results); @@ -558,6 +610,26 @@ public class DeviceRendererServiceImpl implements DeviceRendererService { .build(); } + @Override + public RendererRollbackOutput rendererRollback(History transactionHistory) { + LOG.info("Rolling back..."); + + Result rollbackResult = new FailedRollbackResult(); + Subscriber deleteSubscriber = new DeleteSubscriber(rollbackResult); + + transactionHistory.rollback( + new DeleteService( + crossConnect, + openRoadmInterfaces, + deleteSubscriber + ) + ); + + LOG.info("Rollback done!"); + + return rollbackResult.renderRollbackOutput(); + } + private boolean alarmSuppressionNodeRegistration(ServicePathInput input) { Map atozrenderingFuture = this.executor.submit( - new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z)); + new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z, + transactionHistory)); LOG.info(RENDERING_DEVICES_Z_A_MSG); sendNotifications( @@ -382,7 +389,8 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations RENDERING_DEVICES_Z_A_MSG); ListenableFuture ztoarenderingFuture = this.executor.submit( - new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A)); + new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A, + transactionHistory)); ListenableFuture> renderingCombinedFuture = Futures.allAsList(atozrenderingFuture, ztoarenderingFuture); @@ -403,16 +411,15 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations } rollbackProcessor.addTask( - new DeviceRenderingRollbackTask( - "AtoZDeviceTask", - ! renderingResults.get(0).isSuccess(), - renderingResults.get(0).getRenderedNodeInterfaces(), - this.deviceRenderer)); - rollbackProcessor.addTask( - new DeviceRenderingRollbackTask("ZtoADeviceTask", - ! renderingResults.get(1).isSuccess(), - renderingResults.get(1).getRenderedNodeInterfaces(), - this.deviceRenderer)); + new NetworkDeviceRenderingRollbackTask( + "RollbackTransactionHistoryTask", + transactionHistory, + ! (renderingResults.get(0).isSuccess() && renderingResults.get(1).isSuccess()), + deviceRenderer, + new RollbackResultMessage() + ) + ); + return renderingResults; } diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/DeviceRenderingTask.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/DeviceRenderingTask.java index 6a30f950d..4b2d7fbed 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/DeviceRenderingTask.java +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/DeviceRenderingTask.java @@ -14,6 +14,7 @@ import org.opendaylight.transportpce.renderer.ServicePathInputData; import org.opendaylight.transportpce.renderer.provisiondevice.DeviceRendererService; import org.opendaylight.transportpce.renderer.provisiondevice.DeviceRenderingResult; import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.History; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.ServicePathOutput; import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.optical.renderer.nodes.Nodes; import org.slf4j.Logger; @@ -26,12 +27,14 @@ public class DeviceRenderingTask implements Callable { private final DeviceRendererService deviceRenderer; private final ServicePathInputData servicePathInputData; private final ServicePathDirection direction; + private final History transactionHistory; public DeviceRenderingTask(DeviceRendererService deviceRenderer, ServicePathInputData servicePathInputData, - ServicePathDirection direction) { + ServicePathDirection direction, History transactionHistory) { this.deviceRenderer = deviceRenderer; this.servicePathInputData = servicePathInputData; this.direction = direction; + this.transactionHistory = transactionHistory; } @Override @@ -43,7 +46,7 @@ public class DeviceRenderingTask implements Callable { case Create: operation = "setup"; output = this.deviceRenderer.setupServicePath(this.servicePathInputData.getServicePathInput(), - this.direction); + this.direction, transactionHistory); olmList = this.servicePathInputData.getNodeLists().getOlmNodeList(); break; case Delete: diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/NetworkDeviceRenderingRollbackTask.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/NetworkDeviceRenderingRollbackTask.java new file mode 100644 index 000000000..4c1faa1e9 --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/NetworkDeviceRenderingRollbackTask.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2024 Smartoptics and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.transportpce.renderer.provisiondevice.tasks; + +import org.opendaylight.transportpce.renderer.provisiondevice.DeviceRendererService; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.History; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackOutput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class NetworkDeviceRenderingRollbackTask extends RollbackTask { + + private final History transactionHistory; + + private final boolean isRollbackNecessary; + + private final DeviceRendererService deviceRendererService; + + private final ResultMessage message; + + private static final Logger LOG = LoggerFactory.getLogger(NetworkDeviceRenderingRollbackTask.class); + + public NetworkDeviceRenderingRollbackTask(String id, History transactionHistory, + boolean isRollbackNecessary, + DeviceRendererService deviceRendererService, ResultMessage message) { + super(id); + this.transactionHistory = transactionHistory; + this.isRollbackNecessary = isRollbackNecessary; + this.deviceRendererService = deviceRendererService; + this.message = message; + } + + @Override + public boolean isRollbackNecessary() { + return isRollbackNecessary; + } + + @Override + public Void call() throws Exception { + + RendererRollbackOutput rollbackOutput = deviceRendererService.rendererRollback(transactionHistory); + + if (! rollbackOutput.getSuccess()) { + LOG.warn("Device rendering rollback of {} was not successful! Failed rollback on {}.", this.getId(), + message.createErrorMessage(rollbackOutput.nonnullFailedToRollback().values())); + } else { + LOG.info("Device rollback of {} successful.", this.getId()); + } + + return null; + } +} diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/ResultMessage.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/ResultMessage.java new file mode 100644 index 000000000..d1540caea --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/ResultMessage.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2024 Smartoptics and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.transportpce.renderer.provisiondevice.tasks; + +import java.util.Collection; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollback; + +public interface ResultMessage { + + /** + * Build an error message for a failed rollback. + */ + String createErrorMessage(Collection failedRollbacks); + +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackResultMessage.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackResultMessage.java new file mode 100644 index 000000000..7fae4c9f5 --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackResultMessage.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2024 Smartoptics and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.transportpce.renderer.provisiondevice.tasks; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollback; + +public class RollbackResultMessage implements ResultMessage { + + @Override + public String createErrorMessage(Collection failedRollbacks) { + List failedRollbackNodes = new ArrayList<>(); + + failedRollbacks.forEach(failedRollback -> { + var intf = failedRollback.getInterface(); + + failedRollbackNodes.add( + failedRollback.getNodeId() + + ": " + + intf == null ? "" : String.join(", ", intf) + ); + }); + + return String.join(System.lineSeparator(), failedRollbackNodes); + } + +} diff --git a/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/RendererServiceOperationsImplTest.java b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/RendererServiceOperationsImplTest.java index 63e347868..fe1973618 100644 --- a/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/RendererServiceOperationsImplTest.java +++ b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/RendererServiceOperationsImplTest.java @@ -101,7 +101,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { .buildServiceImplementationRequestInputTerminationPointResource(StringConstants.TTP_TOKEN); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, false).get(); assertEquals(ResponseCodes.RESPONSE_OK, result.getConfigurationResponseCommon().getResponseCode()); @@ -113,7 +113,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { .buildServiceImplementationRequestInputTerminationPointResource(StringConstants.TTP_TOKEN); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); doReturn(RpcResultBuilder.failed().buildFuture()).when(this.olmService).servicePowerSetup(any()); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, false).get(); @@ -126,7 +126,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { .buildServiceImplementationRequestInputTerminationPointResource(StringConstants.PP_TOKEN); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, false).get(); assertEquals(ResponseCodes.RESPONSE_OK, result.getConfigurationResponseCommon().getResponseCode()); @@ -138,7 +138,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { .buildServiceImplementationRequestInputTerminationPointResource(StringConstants.NETWORK_TOKEN); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, false).get(); assertEquals(ResponseCodes.RESPONSE_OK, result.getConfigurationResponseCommon().getResponseCode()); @@ -150,7 +150,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { .buildServiceImplementationRequestInputTerminationPointResource(StringConstants.CLIENT_TOKEN); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, false).get(); assertEquals(ResponseCodes.RESPONSE_OK, result.getConfigurationResponseCommon().getResponseCode()); @@ -167,7 +167,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("failed") .setSuccess(false); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); for (String tpToken : interfaceTokens) { ServiceImplementationRequestInput input = ServiceDataUtils @@ -247,7 +247,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { when(this.olmService.getPm(eq(getPmInputA))).thenReturn(RpcResultBuilder.success(getPmOutput).buildFuture()); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestInput input = ServiceDataUtils .buildServiceImplementationRequestInputTerminationPointResource(StringConstants.NETWORK_TOKEN); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, @@ -263,7 +263,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { when(this.olmService.getPm(any())).thenReturn(RpcResultBuilder.success(getPmOutput1).buildFuture()); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, false).get(); assertEquals(ResponseCodes.RESPONSE_OK, result.getConfigurationResponseCommon().getResponseCode()); @@ -277,7 +277,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { when(this.olmService.getPm(any())).thenReturn(RpcResultBuilder.success(getPmOutput).buildFuture()); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input, false).get(); assertEquals(ResponseCodes.RESPONSE_OK, result.getConfigurationResponseCommon().getResponseCode()); @@ -298,7 +298,7 @@ public class RendererServiceOperationsImplTest extends AbstractTest { doReturn(RpcResultBuilder.success(getPmOutput).buildFuture()).when(this.olmService).getPm(any()); ServicePathOutputBuilder mockOutputBuilder = new ServicePathOutputBuilder().setResult("success") .setSuccess(true); - doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any()); + doReturn(mockOutputBuilder.build()).when(this.deviceRenderer).setupServicePath(any(), any(), any()); ServiceImplementationRequestInput input = ServiceDataUtils .buildServiceImplementationRequestInputTerminationPointResource(StringConstants.NETWORK_TOKEN); ServiceImplementationRequestOutput result = this.rendererServiceOperations.serviceImplementation(input,