SH-Renderer API code to handle OTN Step 1
[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: // 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) // Since service-rate could be null
140                             && (input.getServiceAEnd().getServiceRate().intValue() == 100)
141                             && (input.getServiceAEnd().getServiceFormat().getName().equals("Ethernet"))) {
142                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
143                                 input.getServiceAEnd().getServiceFormat(), input.getServiceAEnd().getServiceRate());
144                             ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
145                                 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
146                             ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
147                                 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
148                             // Rollback should be same for all conditions, so creating a new one
149                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
150                             List<DeviceRenderingResult> renderingResults =
151                                 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
152                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
153                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
154                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
155                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
156                                     OPERATION_FAILED);
157                             }
158                             ServicePowerSetupInput olmPowerSetupInputAtoZ =
159                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(),
160                                     input);
161                             ServicePowerSetupInput olmPowerSetupInputZtoA =
162                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(),
163                                     input);
164                             olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
165                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
166                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
167                                     input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
168                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
169                                     OPERATION_FAILED);
170                             }
171                             // run service activation test twice - once on source node and once on
172                             // destination node
173                             List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
174                             if ((nodes == null) || (nodes.isEmpty())) {
175                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
176                                     OPERATION_FAILED);
177                             }
178                             Nodes sourceNode = nodes.get(0);
179                             Nodes destNode = nodes.get(nodes.size() - 1);
180                             String srcNetworkTp;
181                             String dstNetowrkTp;
182                             if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
183                                 srcNetworkTp = sourceNode.getDestTp();
184                             } else {
185                                 srcNetworkTp = sourceNode.getSrcTp();
186                             }
187                             if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
188                                 dstNetowrkTp = destNode.getDestTp();
189                             } else {
190                                 dstNetowrkTp = destNode.getSrcTp();
191                             }
192                             if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
193                                 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
194                                 rollbackProcessor.rollbackAll();
195                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
196                                     input.getServiceName(), RpcStatusEx.Failed,
197                                     "Service activation test failed.");
198                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
199                                     OPERATION_FAILED);
200                             }
201                             // If Service activation is success update Network ModelMappingUtils
202                             networkModelWavelengthService.useWavelengths(input.getPathDescription());
203                             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
204                                 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
205                         } else { // This implies, service-rate is 1 or 10G
206                             // This includes the lower-order odu (1 G, 10 G) and
207                             LOG.info("RPC implementation for LO-ODU");
208                             String serviceRate = ""; // Assuming service at A-side and Z-side has same service rate
209                             if (input.getServiceAEnd().getServiceRate() != null) {
210                                 serviceRate = input.getServiceAEnd().getServiceRate().toString() + "G";
211                             }
212                             LOG.info("Start rendering for {} service with {} rate and {} format",
213                                 input.getServiceName(), serviceRate,
214                                 input.getServiceAEnd().getServiceFormat());
215                             // TODO: Need to create OCH-OTU4 interfaces by calling service-path input without src-tp
216                             // This is A-Z side
217                             OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
218                                 .rendererCreateOtnServiceInput(input.getServiceName(),
219                                     input.getServiceAEnd().getServiceFormat().getName(),
220                                     serviceRate, input.getPathDescription(), true);
221                             // This is Z-A side
222                             OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
223                                 .rendererCreateOtnServiceInput(input.getServiceName(),
224                                     input.getServiceZEnd().getServiceFormat().getName(),
225                                     serviceRate, input.getPathDescription(), false);
226                             // Rollback should be same for all conditions, so creating a new one
227                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
228                             List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
229                                 otnServicePathInputAtoZ, otnServicePathInputZtoA);
230                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
231                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
232                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
233                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
234                                     OPERATION_FAILED);
235                             }
236                             LOG.info("OTN rendering result size {}", otnRenderingResults.size());
237                             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
238                                 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
239                         }
240                         break;
241                     case Infrastructure:
242                         LOG.info("RPC implementation for {}", input.getConnectionType());
243                         if ((input.getServiceAEnd().getOtuServiceRate() != null)
244                             && (input.getServiceAEnd().getOtuServiceRate().equals(OTU4.class))) {
245                             // For the service of OTU4 infrastructure
246                             // First create the OCH and OTU interfaces
247                             String serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
248                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
249                                 input.getServiceAEnd().getOtuServiceRate(), serviceRate);
250                             // First render OCH and OTU interfaces
251                             ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
252                                 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
253                             ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
254                                 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
255                             // Rollback should be same for all conditions, so creating a new one
256                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
257                             List<DeviceRenderingResult> renderingResults =
258                                 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
259                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
260                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
261                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
262                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
263                                     OPERATION_FAILED);
264                             }
265                             LOG.info("Starting the OLM power setup");
266                             ServicePowerSetupInput olmPowerSetupInputAtoZ =
267                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(),
268                                     input);
269                             ServicePowerSetupInput olmPowerSetupInputZtoA =
270                                 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(),
271                                     input);
272                             olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
273                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
274                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
275                                     input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
276                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
277                                     OPERATION_FAILED);
278                             }
279                             // run service activation test twice - once on source node and once on
280                             // destination node
281                             List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
282                             if ((nodes == null) || (nodes.isEmpty())) {
283                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
284                                     OPERATION_FAILED);
285                             }
286                             Nodes srcNode = nodes.get(0);
287                             Nodes tgtNode = nodes.get(nodes.size() - 1); // destination node or target node
288                             String srcNetworkTp = srcNode.getDestTp(); // In this case srcNode only has destTp
289                             String tgtNetowrkTp = tgtNode.getSrcTp(); // tgtNode node only has srcTp
290
291                             if (!isServiceActivated(srcNode.getNodeId(), srcNetworkTp)
292                                 || !isServiceActivated(tgtNode.getNodeId(), tgtNetowrkTp)) {
293                                 rollbackProcessor.rollbackAll();
294                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
295                                     input.getServiceName(), RpcStatusEx.Failed,
296                                     "Service activation test failed.");
297                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
298                                     OPERATION_FAILED);
299                             }
300                         }
301                         if ((input.getServiceAEnd().getOduServiceRate() != null)
302                             && (input.getServiceAEnd().getOduServiceRate().equals(ODU4.class))) {
303                             // For the service of OTU4 infrastructure
304                             // First create the OCH and OTU interfaces
305                             String serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
306                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
307                                 input.getServiceAEnd().getOtuServiceRate(), serviceRate);
308                             // Now start rendering ODU4 interface
309                             String serviceFormat = "ODU"; // Since we need to create ODU4 Ttp interfaces as well
310                             // This is A-Z side
311                             OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
312                                 .rendererCreateOtnServiceInput(input.getServiceName(),
313                                     serviceFormat, serviceRate, input.getPathDescription(), true);
314                             // This is Z-A side
315                             OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
316                                 .rendererCreateOtnServiceInput(input.getServiceName(),
317                                     input.getServiceZEnd().getServiceFormat().getName(),
318                                     serviceRate, input.getPathDescription(), false);
319                             // Rollback should be same for all conditions, so creating a new one
320                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
321                             List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
322                                 otnServicePathInputAtoZ, otnServicePathInputZtoA);
323                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
324                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
325                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
326                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
327                                     OPERATION_FAILED);
328                             }
329                             LOG.info("OTN rendering result size {}", otnRenderingResults.size());
330                             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
331                                 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
332                         }
333                         break;
334                     default:
335                         LOG.warn("Unsupported connection type {}", input.getConnectionType());
336                 }
337                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
338                     OPERATION_SUCCESSFUL);
339             }
340
341         });
342     }
343
344     @Override
345     @SuppressWarnings("checkstyle:IllegalCatch")
346     public OperationResult reserveResource(PathDescription pathDescription) {
347
348         try {
349             LOG.info("Reserving resources in network model");
350             networkModelWavelengthService.useWavelengths(pathDescription);
351         } catch (Exception e) {
352             LOG.warn("Reserving resources in network model failed");
353             return OperationResult.failed("Resources reserve failed in network model");
354         }
355         return OperationResult.ok("Resources reserved successfully in network model");
356     }
357
358     @Override
359     @SuppressWarnings("checkstyle:IllegalCatch")
360     public OperationResult freeResource(PathDescription pathDescription) {
361
362         try {
363             networkModelWavelengthService.freeWavelengths(pathDescription);
364         } catch (Exception e) {
365             return OperationResult.failed("Resources reserve failed in network model");
366         }
367         return OperationResult.ok("Resources reserved successfully in network model");
368     }
369
370     @Override
371     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input) {
372         String serviceName = input.getServiceName();
373         LOG.info("Calling service delete request {}", input.getServiceName());
374         return executor.submit(new Callable<ServiceDeleteOutput>() {
375
376             @Override
377             public ServiceDeleteOutput call() throws Exception {
378                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
379                         RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
380                 // Obtain path description
381                 Optional<PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
382                 PathDescription pathDescription;
383                 if (pathDescriptionOpt.isPresent()) {
384                     pathDescription = pathDescriptionOpt.get();
385                 } else {
386                     LOG.error("Unable to get path description for service {}!", serviceName);
387                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
388                             RpcStatusEx.Failed, "Unable to get path description for service");
389                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
390                             OPERATION_FAILED);
391                 }
392                 ServicePathInputData servicePathInputDataAtoZ =
393                         ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription);
394                 ServicePathInputData servicePathInputDataZtoA =
395                         ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription);
396                 // OLM turn down power
397                 try {
398                     LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
399                     sendNotifications(ServicePathNotificationTypes.ServiceDelete,
400                             input.getServiceName(), RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
401                     ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
402                     // TODO add some flag rather than string
403                     if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
404                         LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
405                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
406                                 input.getServiceName(), RpcStatusEx.Failed,
407                                 "Service power turndown failed on A-to-Z path for service");
408                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
409                                 OPERATION_FAILED);
410                     }
411                     LOG.debug("Turning down power on Z-to-A path");
412                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
413                             RpcStatusEx.Pending, "Turning down power on Z-to-A path");
414                     ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
415                     // TODO add some flag rather than string
416                     if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
417                         LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
418                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
419                                 input.getServiceName(), RpcStatusEx.Failed,
420                                 "Service power turndown failed on Z-to-A path for service");
421                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
422                                 OPERATION_FAILED);
423                     }
424                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
425                     LOG.error("Error while turning down power!", e);
426                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
427                             OPERATION_FAILED);
428                 }
429                 // delete service path with renderer
430                 LOG.debug("Deleting service path via renderer");
431                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
432                         RpcStatusEx.Pending, "Deleting service path via renderer");
433                 deviceRenderer.deleteServicePath(servicePathInputDataAtoZ.getServicePathInput());
434                 deviceRenderer.deleteServicePath(servicePathInputDataZtoA.getServicePathInput());
435                 networkModelWavelengthService.freeWavelengths(pathDescription);
436                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
437                         RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
438                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
439             }
440         });
441
442
443     }
444
445     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
446             value = "UPM_UNCALLED_PRIVATE_METHOD",
447             justification = "call in call() method")
448     private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
449             throws InterruptedException, ExecutionException, TimeoutException {
450         LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
451         Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
452                 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
453         return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
454     }
455
456     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
457             value = "UPM_UNCALLED_PRIVATE_METHOD",
458             justification = "call in call() method")
459     private Optional<PathDescription> getPathDescriptionFromDatastore(String serviceName) {
460         InstanceIdentifier<PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
461                 .child(ServicePaths.class, new ServicePathsKey(serviceName)).child(PathDescription.class);
462         ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
463         try {
464             LOG.debug("Getting path description for service {}", serviceName);
465             return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
466                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
467         } catch (InterruptedException | ExecutionException | TimeoutException e) {
468             LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
469                     serviceName, e);
470             return Optional.empty();
471         }
472     }
473
474     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
475             value = "UPM_UNCALLED_PRIVATE_METHOD",
476             justification = "call in call() method")
477     private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
478             ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
479         LOG.info(RENDERING_DEVICES_A_Z_MSG);
480         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
481                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
482                 RENDERING_DEVICES_A_Z_MSG);
483         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
484                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
485                         ServicePathDirection.A_TO_Z));
486
487         LOG.info("Rendering devices Z-A");
488         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
489                 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
490                 RENDERING_DEVICES_Z_A_MSG);
491         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
492                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
493                         ServicePathDirection.Z_TO_A));
494         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
495                 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
496
497         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
498         try {
499             LOG.info("Waiting for A-Z and Z-A device renderers ...");
500             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
501         } catch (InterruptedException | ExecutionException | TimeoutException e) {
502             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
503             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
504                     servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
505                     DEVICE_RENDERING_ROLL_BACK_MSG);
506             //FIXME we can't do rollback here, because we don't have rendering results.
507             return renderingResults;
508         }
509
510         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
511                 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
512                 this.deviceRenderer));
513         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
514                 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
515                 this.deviceRenderer));
516         return renderingResults;
517     }
518
519     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
520         value = "UPM_UNCALLED_PRIVATE_METHOD",
521         justification = "call in call() method")
522     private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
523         OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA) {
524         LOG.info(RENDERING_DEVICES_A_Z_MSG);
525         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
526             otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
527             RENDERING_DEVICES_A_Z_MSG);
528         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
529             this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ));
530
531         LOG.info("Rendering devices Z-A");
532         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
533             otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
534             RENDERING_DEVICES_Z_A_MSG);
535         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
536             this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
537         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
538             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
539
540         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
541         try {
542             LOG.info("Waiting for A-Z and Z-A device renderers ...");
543             otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
544         } catch (InterruptedException | ExecutionException | TimeoutException e) {
545             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
546             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
547                 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
548                 DEVICE_RENDERING_ROLL_BACK_MSG);
549             //FIXME we can't do rollback here, because we don't have rendering results.
550             return otnRenderingResults;
551         }
552
553         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
554             ! otnRenderingResults.get(0).isSuccess(), otnRenderingResults.get(0).getRenderedNodeInterfaces(),
555             this.deviceRenderer));
556         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
557             ! otnRenderingResults.get(1).isSuccess(), otnRenderingResults.get(1).getRenderedNodeInterfaces(),
558             this.deviceRenderer));
559
560
561         return otnRenderingResults;
562
563     }
564
565     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
566             value = "UPM_UNCALLED_PRIVATE_METHOD",
567             justification = "call in call() method")
568     private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
569             ServicePowerSetupInput powerSetupInputZtoA) {
570         LOG.info("Olm power setup A-Z");
571         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
572                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
573         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
574                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
575
576         LOG.info("OLM power setup Z-A");
577         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
578                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
579         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
580                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
581         ListenableFuture<List<OLMRenderingResult>> olmFutures =
582                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
583
584         List<OLMRenderingResult> olmResults;
585         try {
586             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
587             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
588         } catch (InterruptedException | ExecutionException | TimeoutException e) {
589             LOG.warn(OLM_ROLL_BACK_MSG, e);
590             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
591                     powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
592                     OLM_ROLL_BACK_MSG);
593             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
594                     this.olmService, powerSetupInputAtoZ));
595             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
596                     this.olmService, powerSetupInputZtoA));
597             return;
598         }
599
600         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
601                 this.olmService, powerSetupInputAtoZ));
602         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
603                 this.olmService, powerSetupInputZtoA));
604     }
605
606     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
607             value = "UPM_UNCALLED_PRIVATE_METHOD",
608             justification = "call in call() method")
609     private boolean isServiceActivated(String nodeId, String tpId) {
610         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
611         for (int i = 0; i < 3; i++) {
612             List<Measurements> measurements = getMeasurements(nodeId, tpId);
613             if ((measurements != null) && verifyPreFecBer(measurements)) {
614                 return true;
615             } else if (measurements == null) {
616                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
617                 return true;
618             } else {
619                 try {
620                     Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
621                 } catch (InterruptedException ex) {
622                     Thread.currentThread().interrupt();
623                 }
624             }
625         }
626         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
627         return false;
628     }
629
630     private List<Measurements> getMeasurements(String nodeId, String tp) {
631         GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder();
632         getPmIpBldr.setNodeId(nodeId);
633         getPmIpBldr.setGranularity(PmGranularity._15min);
634         ResourceIdentifierBuilder rsrcBldr = new ResourceIdentifierBuilder();
635         rsrcBldr.setResourceName(tp + "-OTU");
636         getPmIpBldr.setResourceIdentifier(rsrcBldr.build());
637         getPmIpBldr.setResourceType(ResourceTypeEnum.Interface);
638
639         try {
640             Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
641             RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
642             GetPmOutput getPmOutput = getPmRpcResult.getResult();
643             if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
644                 LOG.info("successfully finished calling OLM's get PM");
645                 return getPmOutput.getMeasurements();
646                 // may return null
647             } else {
648                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
649             }
650
651         } catch (ExecutionException | InterruptedException e) {
652             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
653         }
654         return null;
655     }
656
657
658     private boolean verifyPreFecBer(List<Measurements> measurements) {
659         double preFecCorrectedErrors = Double.MIN_VALUE;
660         double fecUncorrectableBlocks = Double.MIN_VALUE;
661
662         for (Measurements measurement : measurements) {
663             if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
664                 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
665             }
666             if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
667                 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
668             }
669         }
670
671         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
672                 fecUncorrectableBlocks);
673
674         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
675             LOG.error("Data has uncorrectable errors, BER test failed");
676             return false;
677         } else {
678             double numOfBitsPerSecond = 112000000000d;
679             double threshold = 0.00002d;
680             double result = preFecCorrectedErrors / numOfBitsPerSecond;
681             LOG.info("PreFEC value is {}", Double.toString(result));
682             return result <= threshold;
683         }
684     }
685
686 }