SH-Renderer API code to handle OTN Step 2
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / RendererServiceOperationsImpl.java
1 /*
2  * Copyright © 2017 AT&T and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.transportpce.renderer.provisiondevice;
9
10 import com.google.common.util.concurrent.Futures;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import com.google.common.util.concurrent.ListeningExecutorService;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Optional;
17 import java.util.concurrent.Callable;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Executors;
20 import java.util.concurrent.Future;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
25 import org.opendaylight.mdsal.binding.api.ReadTransaction;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.transportpce.common.OperationResult;
28 import org.opendaylight.transportpce.common.ResponseCodes;
29 import org.opendaylight.transportpce.common.StringConstants;
30 import org.opendaylight.transportpce.common.Timeouts;
31 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
32 import org.opendaylight.transportpce.renderer.NetworkModelWavelengthService;
33 import org.opendaylight.transportpce.renderer.ServicePathInputData;
34 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
35 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
36 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmInputBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmOutput;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerSetupInput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownInputBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownOutput;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.get.pm.output.Measurements;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.device.rev200128.OtnServicePathInput;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev200520.ServiceDeleteInput;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev200520.ServiceDeleteOutput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev200520.ServiceImplementationRequestInput;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev200520.ServiceImplementationRequestOutput;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev200520.ServiceRpcResultSp;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev200520.ServiceRpcResultSpBuilder;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev181130.ODU4;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev181130.OTU4;
57 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
58 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
59 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
60 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.ServicePathNotificationTypes;
61 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service.path.PathDescription;
62 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
63 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
64 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
65 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev200615.olm.get.pm.input.ResourceIdentifierBuilder;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev200615.olm.renderer.input.Nodes;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.opendaylight.yangtools.yang.common.RpcResult;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72
73 public class RendererServiceOperationsImpl implements RendererServiceOperations {
74
75     private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
76             "Device rendering was not successful! Rendering will be rolled back.";
77     private static final String OLM_ROLL_BACK_MSG =
78             "OLM power setup was not successful! Rendering and OLM will be rolled back.";
79     private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
80     private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
81     private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
82     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
83     private static final String FAILED = "Failed";
84     private static final String OPERATION_FAILED = "Operation Failed";
85     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
86     private static final int NUMBER_OF_THREADS = 4;
87
88     private final DeviceRendererService deviceRenderer;
89     private final OtnDeviceRendererService otnDeviceRenderer;
90     private final TransportpceOlmService olmService;
91     private final DataBroker dataBroker;
92     private final NotificationPublishService notificationPublishService;
93     private ListeningExecutorService executor;
94     private NetworkModelWavelengthService networkModelWavelengthService;
95     private ServiceRpcResultSp notification = null;
96
97     public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
98             OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
99             DataBroker dataBroker, NetworkModelWavelengthService networkModelWavelengthService,
100             NotificationPublishService notificationPublishService) {
101         this.deviceRenderer = deviceRenderer;
102         this.otnDeviceRenderer = otnDeviceRenderer;
103         this.olmService = olmService;
104         this.dataBroker = dataBroker;
105         this.networkModelWavelengthService = networkModelWavelengthService;
106         this.notificationPublishService = notificationPublishService;
107         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
108     }
109
110     private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
111             RpcStatusEx rpcStatusEx, String message) {
112         this.notification = new ServiceRpcResultSpBuilder()
113                 .setNotificationType(servicePathNotificationTypes)
114                 .setServiceName(serviceName)
115                 .setStatus(rpcStatusEx)
116                 .setStatusMessage(message)
117                 .build();
118         try {
119             notificationPublishService.putNotification(this.notification);
120         } catch (InterruptedException e) {
121             LOG.info("notification offer rejected: ", e);
122         }
123     }
124
125     @Override
126     public ListenableFuture<ServiceImplementationRequestOutput>
127             serviceImplementation(ServiceImplementationRequestInput input) {
128         LOG.info("Calling service impl request {}", input.getServiceName());
129         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
130             @Override
131             public ServiceImplementationRequestOutput call() throws Exception {
132                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
133                         RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
134                 // Here is the switch statement that distinguishes on the connection-type
135                 LOG.info("Connection-type is {} for {}", input.getConnectionType(), input.getServiceName());
136                 switch (input.getConnectionType()) {
137                     case Service: case RoadmLine: // This takes into account of Ethernet 100G, 1G, 10G and ODU4
138                         LOG.info("RPC implementation for {}", input.getConnectionType());
139                         if (((input.getServiceAEnd().getServiceRate() != null)
140                             && (input.getServiceAEnd().getServiceRate().intValue() == 100))
141                             && ((input.getServiceAEnd().getServiceFormat().getName().equals("Ethernet"))
142                                 || (input.getServiceAEnd().getServiceFormat().getName().equals("OC")))) {
143                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
144                                 input.getServiceAEnd().getServiceFormat(), input.getServiceAEnd().getServiceRate());
145                             ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
146                                 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
147                             ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
148                                 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
149                             // Rollback should be same for all conditions, so creating a new one
150                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
151                             List<DeviceRenderingResult> renderingResults =
152                                 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
153                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
154                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
155                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
156                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
157                                     OPERATION_FAILED);
158                             }
159                             ServicePowerSetupInput olmPowerSetupInputAtoZ =
160                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(),
161                                     input);
162                             ServicePowerSetupInput olmPowerSetupInputZtoA =
163                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(),
164                                     input);
165                             olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
166                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
167                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
168                                     input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
169                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
170                                     OPERATION_FAILED);
171                             }
172                             // run service activation test twice - once on source node and once on
173                             // destination node
174                             List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
175                             if ((nodes == null) || (nodes.isEmpty())) {
176                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
177                                     OPERATION_FAILED);
178                             }
179                             Nodes sourceNode = nodes.get(0);
180                             Nodes destNode = nodes.get(nodes.size() - 1);
181                             String srcNetworkTp;
182                             String dstNetowrkTp;
183                             if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
184                                 srcNetworkTp = sourceNode.getDestTp();
185                             } else {
186                                 srcNetworkTp = sourceNode.getSrcTp();
187                             }
188                             if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
189                                 dstNetowrkTp = destNode.getDestTp();
190                             } else {
191                                 dstNetowrkTp = destNode.getSrcTp();
192                             }
193                             if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
194                                 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
195                                 rollbackProcessor.rollbackAll();
196                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
197                                     input.getServiceName(), RpcStatusEx.Failed,
198                                     "Service activation test failed.");
199                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
200                                     OPERATION_FAILED);
201                             }
202                             // If Service activation is success update Network ModelMappingUtils
203                             networkModelWavelengthService.useWavelengths(input.getPathDescription());
204                         } else { // This implies, service-rate is 1 or 10G
205                             // This includes the lower-order odu (1 G, 10 G) and
206                             LOG.info("RPC implementation for LO-ODU");
207                             String serviceRate = ""; // Assuming service at A-side and Z-side has same service rate
208                             if (input.getServiceAEnd().getServiceRate() != null) {
209                                 serviceRate = input.getServiceAEnd().getServiceRate().toString() + "G";
210                             }
211                             LOG.info("Start rendering for {} service with {} rate and {} format",
212                                 input.getServiceName(), serviceRate,
213                                 input.getServiceAEnd().getServiceFormat());
214                             // TODO: Need to create OCH-OTU4 interfaces by calling service-path input without src-tp
215                             // This is A-Z side
216                             OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
217                                 .rendererCreateOtnServiceInput(input.getServiceName(),
218                                     input.getServiceAEnd().getServiceFormat().getName(),
219                                     serviceRate, input.getPathDescription(), true);
220                             // This is Z-A side
221                             OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
222                                 .rendererCreateOtnServiceInput(input.getServiceName(),
223                                     input.getServiceZEnd().getServiceFormat().getName(),
224                                     serviceRate, input.getPathDescription(), false);
225                             // Rollback should be same for all conditions, so creating a new one
226                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
227                             List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
228                                 otnServicePathInputAtoZ, otnServicePathInputZtoA);
229                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
230                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
231                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
232                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
233                                     OPERATION_FAILED);
234                             }
235                             LOG.info("OTN rendering result size {}", otnRenderingResults.size());
236                         }
237                         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
238                             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
239                         break;
240                     case Infrastructure:
241                         LOG.info("RPC implementation for {}", input.getConnectionType());
242                         if ((input.getServiceAEnd().getOtuServiceRate() != null)
243                             && (input.getServiceAEnd().getOtuServiceRate().equals(OTU4.class))) {
244                             // For the service of OTU4 infrastructure
245                             // First create the OCH and OTU interfaces
246                             String serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
247                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
248                                 input.getServiceAEnd().getOtuServiceRate(), serviceRate);
249                             // First render OCH and OTU interfaces
250                             ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
251                                 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
252                             ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
253                                 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
254                             // Rollback should be same for all conditions, so creating a new one
255                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
256                             List<DeviceRenderingResult> renderingResults =
257                                 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
258                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
259                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
260                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
261                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
262                                     OPERATION_FAILED);
263                             }
264                             LOG.info("Starting the OLM power setup");
265                             ServicePowerSetupInput olmPowerSetupInputAtoZ =
266                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(),
267                                     input);
268                             ServicePowerSetupInput olmPowerSetupInputZtoA =
269                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(),
270                                     input);
271                             olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
272                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
273                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
274                                     input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
275                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
276                                     OPERATION_FAILED);
277                             }
278                             // run service activation test twice - once on source node and once on
279                             // destination node
280                             List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
281                             if ((nodes == null) || (nodes.isEmpty())) {
282                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
283                                     OPERATION_FAILED);
284                             }
285                             Nodes srcNode = nodes.get(0);
286                             Nodes tgtNode = nodes.get(nodes.size() - 1); // destination node or target node
287                             String srcNetworkTp = srcNode.getDestTp(); // In this case srcNode only has destTp
288                             String tgtNetowrkTp = tgtNode.getSrcTp(); // tgtNode node only has srcTp
289
290                             if (!isServiceActivated(srcNode.getNodeId(), srcNetworkTp)
291                                 || !isServiceActivated(tgtNode.getNodeId(), tgtNetowrkTp)) {
292                                 rollbackProcessor.rollbackAll();
293                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
294                                     input.getServiceName(), RpcStatusEx.Failed,
295                                     "Service activation test failed.");
296                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
297                                     OPERATION_FAILED);
298                             }
299                         }
300                         if ((input.getServiceAEnd().getOduServiceRate() != null)
301                             && (input.getServiceAEnd().getOduServiceRate().equals(ODU4.class))) {
302                             // For the service of OTU4 infrastructure
303                             // First create the OCH and OTU interfaces
304                             String serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
305                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
306                                 input.getServiceAEnd().getOduServiceRate(), serviceRate);
307                             // Now start rendering ODU4 interface
308                             String serviceFormat = "ODU"; // Since we need to create ODU4 Ttp interfaces as well
309                             // This is A-Z side
310                             OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
311                                 .rendererCreateOtnServiceInput(input.getServiceName(),
312                                     serviceFormat, serviceRate, input.getPathDescription(), true);
313                             // This is Z-A side
314                             OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
315                                 .rendererCreateOtnServiceInput(input.getServiceName(),
316                                     input.getServiceZEnd().getServiceFormat().getName(),
317                                     serviceRate, input.getPathDescription(), false);
318                             // Rollback should be same for all conditions, so creating a new one
319                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
320                             List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
321                                 otnServicePathInputAtoZ, otnServicePathInputZtoA);
322                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
323                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
324                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
325                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
326                                     OPERATION_FAILED);
327                             }
328                             LOG.info("OTN rendering result size {}", otnRenderingResults.size());
329                             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
330                                 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
331                         }
332                         break;
333                     default:
334                         LOG.warn("Unsupported connection type {}", input.getConnectionType());
335                 }
336                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
337                     OPERATION_SUCCESSFUL);
338             }
339
340         });
341     }
342
343     @Override
344     @SuppressWarnings("checkstyle:IllegalCatch")
345     public OperationResult reserveResource(PathDescription pathDescription) {
346
347         try {
348             LOG.info("Reserving resources in network model");
349             networkModelWavelengthService.useWavelengths(pathDescription);
350         } catch (Exception e) {
351             LOG.warn("Reserving resources in network model failed");
352             return OperationResult.failed("Resources reserve failed in network model");
353         }
354         return OperationResult.ok("Resources reserved successfully in network model");
355     }
356
357     @Override
358     @SuppressWarnings("checkstyle:IllegalCatch")
359     public OperationResult freeResource(PathDescription pathDescription) {
360
361         try {
362             networkModelWavelengthService.freeWavelengths(pathDescription);
363         } catch (Exception e) {
364             return OperationResult.failed("Resources reserve failed in network model");
365         }
366         return OperationResult.ok("Resources reserved successfully in network model");
367     }
368
369     @Override
370     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input) {
371         String serviceName = input.getServiceName();
372         LOG.info("Calling service delete request {}", input.getServiceName());
373         return executor.submit(new Callable<ServiceDeleteOutput>() {
374
375             @Override
376             public ServiceDeleteOutput call() throws Exception {
377                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
378                         RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
379                 // Obtain path description
380                 Optional<PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
381                 PathDescription pathDescription;
382                 if (pathDescriptionOpt.isPresent()) {
383                     pathDescription = pathDescriptionOpt.get();
384                 } else {
385                     LOG.error("Unable to get path description for service {}!", serviceName);
386                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
387                             RpcStatusEx.Failed, "Unable to get path description for service");
388                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
389                             OPERATION_FAILED);
390                 }
391                 ServicePathInputData servicePathInputDataAtoZ =
392                         ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription);
393                 ServicePathInputData servicePathInputDataZtoA =
394                         ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription);
395                 // OLM turn down power
396                 try {
397                     LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
398                     sendNotifications(ServicePathNotificationTypes.ServiceDelete,
399                             input.getServiceName(), RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
400                     ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
401                     // TODO add some flag rather than string
402                     if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
403                         LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
404                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
405                                 input.getServiceName(), RpcStatusEx.Failed,
406                                 "Service power turndown failed on A-to-Z path for service");
407                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
408                                 OPERATION_FAILED);
409                     }
410                     LOG.debug("Turning down power on Z-to-A path");
411                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
412                             RpcStatusEx.Pending, "Turning down power on Z-to-A path");
413                     ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
414                     // TODO add some flag rather than string
415                     if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
416                         LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
417                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
418                                 input.getServiceName(), RpcStatusEx.Failed,
419                                 "Service power turndown failed on Z-to-A path for service");
420                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
421                                 OPERATION_FAILED);
422                     }
423                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
424                     LOG.error("Error while turning down power!", e);
425                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
426                             OPERATION_FAILED);
427                 }
428                 // delete service path with renderer
429                 LOG.debug("Deleting service path via renderer");
430                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
431                         RpcStatusEx.Pending, "Deleting service path via renderer");
432                 deviceRenderer.deleteServicePath(servicePathInputDataAtoZ.getServicePathInput());
433                 deviceRenderer.deleteServicePath(servicePathInputDataZtoA.getServicePathInput());
434                 networkModelWavelengthService.freeWavelengths(pathDescription);
435                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
436                         RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
437                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
438             }
439         });
440
441
442     }
443
444     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
445             value = "UPM_UNCALLED_PRIVATE_METHOD",
446             justification = "call in call() method")
447     private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
448             throws InterruptedException, ExecutionException, TimeoutException {
449         LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
450         Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
451                 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
452         return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
453     }
454
455     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
456             value = "UPM_UNCALLED_PRIVATE_METHOD",
457             justification = "call in call() method")
458     private Optional<PathDescription> getPathDescriptionFromDatastore(String serviceName) {
459         InstanceIdentifier<PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
460                 .child(ServicePaths.class, new ServicePathsKey(serviceName)).child(PathDescription.class);
461         ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
462         try {
463             LOG.debug("Getting path description for service {}", serviceName);
464             return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
465                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
466         } catch (InterruptedException | ExecutionException | TimeoutException e) {
467             LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
468                     serviceName, e);
469             return Optional.empty();
470         }
471     }
472
473     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
474             value = "UPM_UNCALLED_PRIVATE_METHOD",
475             justification = "call in call() method")
476     private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
477             ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
478         LOG.info(RENDERING_DEVICES_A_Z_MSG);
479         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
480                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
481                 RENDERING_DEVICES_A_Z_MSG);
482         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
483                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
484                         ServicePathDirection.A_TO_Z));
485
486         LOG.info("Rendering devices Z-A");
487         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
488                 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
489                 RENDERING_DEVICES_Z_A_MSG);
490         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
491                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
492                         ServicePathDirection.Z_TO_A));
493         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
494                 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
495
496         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
497         try {
498             LOG.info("Waiting for A-Z and Z-A device renderers ...");
499             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
500         } catch (InterruptedException | ExecutionException | TimeoutException e) {
501             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
502             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
503                     servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
504                     DEVICE_RENDERING_ROLL_BACK_MSG);
505             //FIXME we can't do rollback here, because we don't have rendering results.
506             return renderingResults;
507         }
508
509         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
510                 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
511                 this.deviceRenderer));
512         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
513                 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
514                 this.deviceRenderer));
515         return renderingResults;
516     }
517
518     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
519         value = "UPM_UNCALLED_PRIVATE_METHOD",
520         justification = "call in call() method")
521     private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
522         OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA) {
523         LOG.info(RENDERING_DEVICES_A_Z_MSG);
524         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
525             otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
526             RENDERING_DEVICES_A_Z_MSG);
527         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
528             this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ));
529
530         LOG.info("Rendering devices Z-A");
531         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
532             otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
533             RENDERING_DEVICES_Z_A_MSG);
534         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
535             this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
536         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
537             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
538
539         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
540         try {
541             LOG.info("Waiting for A-Z and Z-A device renderers ...");
542             otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
543         } catch (InterruptedException | ExecutionException | TimeoutException e) {
544             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
545             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
546                 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
547                 DEVICE_RENDERING_ROLL_BACK_MSG);
548             //FIXME we can't do rollback here, because we don't have rendering results.
549             return otnRenderingResults;
550         }
551
552         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
553             ! otnRenderingResults.get(0).isSuccess(), otnRenderingResults.get(0).getRenderedNodeInterfaces(),
554             this.deviceRenderer));
555         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
556             ! otnRenderingResults.get(1).isSuccess(), otnRenderingResults.get(1).getRenderedNodeInterfaces(),
557             this.deviceRenderer));
558
559
560         return otnRenderingResults;
561
562     }
563
564     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
565             value = "UPM_UNCALLED_PRIVATE_METHOD",
566             justification = "call in call() method")
567     private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
568             ServicePowerSetupInput powerSetupInputZtoA) {
569         LOG.info("Olm power setup A-Z");
570         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
571                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
572         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
573                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
574
575         LOG.info("OLM power setup Z-A");
576         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
577                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
578         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
579                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
580         ListenableFuture<List<OLMRenderingResult>> olmFutures =
581                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
582
583         List<OLMRenderingResult> olmResults;
584         try {
585             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
586             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
587         } catch (InterruptedException | ExecutionException | TimeoutException e) {
588             LOG.warn(OLM_ROLL_BACK_MSG, e);
589             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
590                     powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
591                     OLM_ROLL_BACK_MSG);
592             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
593                     this.olmService, powerSetupInputAtoZ));
594             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
595                     this.olmService, powerSetupInputZtoA));
596             return;
597         }
598
599         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
600                 this.olmService, powerSetupInputAtoZ));
601         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
602                 this.olmService, powerSetupInputZtoA));
603     }
604
605     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
606             value = "UPM_UNCALLED_PRIVATE_METHOD",
607             justification = "call in call() method")
608     private boolean isServiceActivated(String nodeId, String tpId) {
609         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
610         for (int i = 0; i < 3; i++) {
611             List<Measurements> measurements = getMeasurements(nodeId, tpId);
612             if ((measurements != null) && verifyPreFecBer(measurements)) {
613                 return true;
614             } else if (measurements == null) {
615                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
616                 return true;
617             } else {
618                 try {
619                     Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
620                 } catch (InterruptedException ex) {
621                     Thread.currentThread().interrupt();
622                 }
623             }
624         }
625         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
626         return false;
627     }
628
629     private List<Measurements> getMeasurements(String nodeId, String tp) {
630         GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder();
631         getPmIpBldr.setNodeId(nodeId);
632         getPmIpBldr.setGranularity(PmGranularity._15min);
633         ResourceIdentifierBuilder rsrcBldr = new ResourceIdentifierBuilder();
634         rsrcBldr.setResourceName(tp + "-OTU");
635         getPmIpBldr.setResourceIdentifier(rsrcBldr.build());
636         getPmIpBldr.setResourceType(ResourceTypeEnum.Interface);
637
638         try {
639             Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
640             RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
641             GetPmOutput getPmOutput = getPmRpcResult.getResult();
642             if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
643                 LOG.info("successfully finished calling OLM's get PM");
644                 return getPmOutput.getMeasurements();
645                 // may return null
646             } else {
647                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
648             }
649
650         } catch (ExecutionException | InterruptedException e) {
651             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
652         }
653         return null;
654     }
655
656
657     private boolean verifyPreFecBer(List<Measurements> measurements) {
658         double preFecCorrectedErrors = Double.MIN_VALUE;
659         double fecUncorrectableBlocks = Double.MIN_VALUE;
660
661         for (Measurements measurement : measurements) {
662             if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
663                 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
664             }
665             if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
666                 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
667             }
668         }
669
670         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
671                 fecUncorrectableBlocks);
672
673         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
674             LOG.error("Data has uncorrectable errors, BER test failed");
675             return false;
676         } else {
677             double numOfBitsPerSecond = 112000000000d;
678             double threshold = 0.00002d;
679             double result = preFecCorrectedErrors / numOfBitsPerSecond;
680             LOG.info("PreFEC value is {}", Double.toString(result));
681             return result <= threshold;
682         }
683     }
684
685 }