Integrate renderer & olm code to run on device221
[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.base.Optional;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.ListeningExecutorService;
14 import com.google.common.util.concurrent.MoreExecutors;
15
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.transportpce.common.OperationResult;
30 import org.opendaylight.transportpce.common.ResponseCodes;
31 import org.opendaylight.transportpce.common.StringConstants;
32 import org.opendaylight.transportpce.common.Timeouts;
33 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
34 import org.opendaylight.transportpce.renderer.NetworkModelWavelengthService;
35 import org.opendaylight.transportpce.renderer.ServicePathInputData;
36 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmInputBuilder;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmOutput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerSetupInput;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownInputBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownOutput;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.get.pm.output.Measurements;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceDeleteInput;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceDeleteOutput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceImplementationRequestInput;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceImplementationRequestOutput;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceRpcResultSp;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceRpcResultSpBuilder;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
57 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev171016.RpcStatusEx;
58 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev171016.ServicePathNotificationTypes;
59 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev171016.service.path.PathDescription;
60 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
61 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
62 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
63 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev170907.olm.get.pm.input.ResourceIdentifierBuilder;
64 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev170907.olm.renderer.input.Nodes;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.RpcResult;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71 public class RendererServiceOperationsImpl implements RendererServiceOperations {
72
73     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
74     private static final String FAILED = "Failed";
75     private static final String OPERATION_FAILED = "Operation Failed";
76     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
77     private static final int NUMBER_OF_THREADS = 4;
78
79     private final DeviceRendererService deviceRenderer;
80     private final TransportpceOlmService olmService;
81     private final DataBroker dataBroker;
82     private final NotificationPublishService notificationPublishService;
83     private ListeningExecutorService executor;
84     private NetworkModelWavelengthService networkModelWavelengthService;
85     private ServiceRpcResultSp notification = null;
86
87     public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer, TransportpceOlmService olmService,
88             DataBroker dataBroker, NetworkModelWavelengthService networkModelWavelengthService,
89             NotificationPublishService notificationPublishService) {
90         this.deviceRenderer = deviceRenderer;
91         this.olmService = olmService;
92         this.dataBroker = dataBroker;
93         this.networkModelWavelengthService = networkModelWavelengthService;
94         this.notificationPublishService = notificationPublishService;
95         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
96     }
97
98     private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
99             RpcStatusEx rpcStatusEx, String message) {
100         this.notification = new ServiceRpcResultSpBuilder()
101                 .setNotificationType(servicePathNotificationTypes)
102                 .setServiceName(serviceName)
103                 .setStatus(rpcStatusEx)
104                 .setStatusMessage(message)
105                 .build();
106         try {
107             notificationPublishService.putNotification(this.notification);
108         } catch (InterruptedException e) {
109             LOG.info("notification offer rejected : ", e.getMessage());
110         }
111     }
112
113 /*    @Override
114     public ServiceImplementationRequestOutput serviceImplementation(ServiceImplementationRequestInput input) {
115         LOG.info("Calling service impl request {} {}", input.getServiceName());
116         RollbackProcessor rollbackProcessor = new RollbackProcessor();
117
118         ServicePathInputData servicePathInputDataAtoZ
119                 = ModelMappingUtils.rendererCreateServiceInputAToZ(input.getServiceName(),
120                         input.getPathDescription());
121         ServicePathInputData servicePathInputDataZtoA
122                 = ModelMappingUtils.rendererCreateServiceInputZToA(input.getServiceName(),
123                         input.getPathDescription());
124         List<DeviceRenderingResult> renderingResults = deviceRendering(rollbackProcessor, servicePathInputDataAtoZ,
125                 servicePathInputDataZtoA);
126         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
127             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
128         }
129
130         ServicePowerSetupInput olmPowerSetupInputAtoZ = ModelMappingUtils.createServicePowerSetupInput(
131                 renderingResults.get(0).getOlmList(), input);
132         ServicePowerSetupInput olmPowerSetupInputZtoA = ModelMappingUtils.createServicePowerSetupInput(
133                 renderingResults.get(1).getOlmList(), input);
134         olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
135         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
136             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
137         }
138
139         // run service activation test twice - once on source node and once on destination node
140         List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
141         Nodes sourceNode = nodes.get(0);
142         Nodes destNode = nodes.get(nodes.size() - 1);
143
144         String srcNetworkTp;
145         String dstNetowrkTp;
146
147         if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
148             srcNetworkTp = sourceNode.getDestTp();
149         } else {
150             srcNetworkTp = sourceNode.getSrcTp();
151         }
152         if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
153             dstNetowrkTp = destNode.getDestTp();
154         } else {
155             dstNetowrkTp = destNode.getSrcTp();
156         }
157
158         if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
159                 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
160             rollbackProcessor.rollbackAll();
161             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
162         }
163     } */
164
165     @Override
166     public ListenableFuture<ServiceImplementationRequestOutput>
167             serviceImplementation(ServiceImplementationRequestInput input) {
168         LOG.info("Calling service impl request {} {}", input.getServiceName());
169         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
170
171             @Override
172             public ServiceImplementationRequestOutput call() throws Exception {
173                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
174                         RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
175                 RollbackProcessor rollbackProcessor = new RollbackProcessor();
176                 ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
177                         .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
178                 ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
179                         .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
180                 List<DeviceRenderingResult> renderingResults =
181                         deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
182                 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
183                     sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
184                             RpcStatusEx.Failed, "Device rendering was not successful! Rendering will be rolled back.");
185                     return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
186                 }
187                 ServicePowerSetupInput olmPowerSetupInputAtoZ =
188                         ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
189                 ServicePowerSetupInput olmPowerSetupInputZtoA =
190                         ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
191                 olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
192                 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
193                     sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
194                             RpcStatusEx.Failed,
195                             "OLM power setup was not successful! Rendering and OLM will be rolled back.");
196                     return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
197                 }
198                 // run service activation test twice - once on source node and once on
199                 // destination node
200                 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
201                 Nodes sourceNode = nodes.get(0);
202                 Nodes destNode = nodes.get(nodes.size() - 1);
203                 String srcNetworkTp;
204                 String dstNetowrkTp;
205                 //if (sourceNode.getDestTp().contains(OpenRoadmInterfacesImpl.NETWORK_TOKEN)) {
206                 if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
207                     srcNetworkTp = sourceNode.getDestTp();
208                 } else {
209                     srcNetworkTp = sourceNode.getSrcTp();
210                 }
211                 //if (destNode.getDestTp().contains(OpenRoadmInterfacesImpl.NETWORK_TOKEN)) {
212                 if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
213                     dstNetowrkTp = destNode.getDestTp();
214                 } else {
215                     dstNetowrkTp = destNode.getSrcTp();
216                 }
217                 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
218                         || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
219                     rollbackProcessor.rollbackAll();
220                     sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
221                             RpcStatusEx.Failed, "Service activation test failed.");
222                     return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
223                 }
224                 // If Service activation is success update Network ModelMappingUtils
225                 networkModelWavelengthService.useWavelengths(input.getPathDescription());
226                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
227                         RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
228                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
229             }
230         });
231
232     }
233
234     @SuppressWarnings("checkstyle:IllegalCatch")
235     public OperationResult reserveResource(PathDescription pathDescription) {
236
237         try {
238             LOG.info("Reserving resources in network model");
239             networkModelWavelengthService.useWavelengths(pathDescription);
240         } catch (Exception e) {
241             LOG.warn("Reserving resources in network model failed");
242             return OperationResult.failed("Resources reserve failed in network model");
243         }
244         return OperationResult.ok("Resources reserved successfully in network model");
245     }
246
247     @SuppressWarnings("checkstyle:IllegalCatch")
248     public OperationResult freeResource(PathDescription pathDescription) {
249
250         try {
251             networkModelWavelengthService.freeWavelengths(pathDescription);
252         } catch (Exception e) {
253             return OperationResult.failed("Resources reserve failed in network model");
254         }
255         return OperationResult.ok("Resources reserved successfully in network model");
256     }
257
258     @Override
259     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input) {
260         String serviceName = input.getServiceName();
261         LOG.info("Calling service delete request {} {}", input.getServiceName());
262         return executor.submit(new Callable<ServiceDeleteOutput>() {
263
264             @Override
265             public ServiceDeleteOutput call() throws Exception {
266                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
267                         RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
268                 // Obtain path description
269                 Optional<PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
270                 PathDescription pathDescription;
271                 if (pathDescriptionOpt.isPresent()) {
272                     pathDescription = pathDescriptionOpt.get();
273                 } else {
274                     LOG.error("Unable to get path description for service {}!", serviceName);
275                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
276                             RpcStatusEx.Failed, "Unable to get path description for service");
277                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
278                             OPERATION_FAILED);
279                 }
280                 ServicePathInputData servicePathInputDataAtoZ =
281                         ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription);
282                 ServicePathInputData servicePathInputDataZtoA =
283                         ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription);
284                 // OLM turn down power
285                 try {
286                     LOG.debug("Turning down power on A-to-Z path");
287                     sendNotifications(ServicePathNotificationTypes.ServiceDelete,
288                             input.getServiceName(), RpcStatusEx.Pending, "Turning down power on A-to-Z path");
289                     ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
290                     // TODO add some flag rather than string
291                     if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
292                         LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
293                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
294                                 input.getServiceName(), RpcStatusEx.Failed,
295                                 "Service power turndown failed on A-to-Z path for service");
296                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
297                                 OPERATION_FAILED);
298                     }
299                     LOG.debug("Turning down power on Z-to-A path");
300                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
301                             RpcStatusEx.Pending, "Turning down power on Z-to-A path");
302                     ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
303                     // TODO add some flag rather than string
304                     if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
305                         LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
306                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
307                                 input.getServiceName(), RpcStatusEx.Failed,
308                                 "Service power turndown failed on Z-to-A path for service");
309                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
310                                 OPERATION_FAILED);
311                     }
312                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
313                     LOG.error("Error while turning down power!", e);
314                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
315                             OPERATION_FAILED);
316                 }
317                 // delete service path with renderer
318                 LOG.debug("Deleting service path via renderer");
319                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
320                         RpcStatusEx.Pending, "Deleting service path via renderer");
321                 deviceRenderer.deleteServicePath(servicePathInputDataAtoZ.getServicePathInput());
322                 deviceRenderer.deleteServicePath(servicePathInputDataZtoA.getServicePathInput());
323                 networkModelWavelengthService.freeWavelengths(pathDescription);
324                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
325                         RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
326                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
327             }
328         });
329
330
331     }
332
333     private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
334             throws InterruptedException, ExecutionException, TimeoutException {
335         LOG.debug("Turning down power on A-to-Z path");
336         Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
337                 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
338         return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
339     }
340
341     private Optional<PathDescription> getPathDescriptionFromDatastore(String serviceName) {
342         InstanceIdentifier<PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
343                 .child(ServicePaths.class, new ServicePathsKey(serviceName)).child(PathDescription.class);
344         ReadOnlyTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
345         try {
346             LOG.debug("Getting path description for service {}", serviceName);
347             return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
348                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
349         } catch (InterruptedException | ExecutionException | TimeoutException e) {
350             LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
351                     serviceName, e);
352             return Optional.absent();
353         }
354     }
355
356     private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
357             ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
358         LOG.info("Rendering devices A-Z");
359         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
360                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
361                 "Rendering devices A-Z");
362         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
363                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
364                         ServicePathDirection.A_TO_Z));
365
366         LOG.info("Rendering devices Z-A");
367         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
368                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
369                 "Rendering devices A-Z");
370         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
371                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
372                         ServicePathDirection.Z_TO_A));
373         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
374                 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
375
376         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
377         try {
378             LOG.info("Waiting for A-Z and Z-A device renderers ...");
379             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
380         } catch (InterruptedException | ExecutionException | TimeoutException e) {
381             LOG.warn("Device rendering was not successful! Rendering will be rolled back.", e);
382             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
383                     servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
384                     "Device rendering was not successful! Rendering will be rolled back.");
385             //FIXME we can't do rollback here, because we don't have rendering results.
386             //rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask", true));
387             //rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask", true));
388             return renderingResults;
389         }
390
391         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
392                 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
393                 this.deviceRenderer));
394         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
395                 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
396                 this.deviceRenderer));
397         return renderingResults;
398     }
399
400     private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
401             ServicePowerSetupInput powerSetupInputZtoA) {
402         LOG.info("Olm power setup A-Z");
403         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
404                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
405         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
406                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
407
408         LOG.info("OLM power setup Z-A");
409         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
410                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
411         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
412                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
413         ListenableFuture<List<OLMRenderingResult>> olmFutures =
414                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
415
416         List<OLMRenderingResult> olmResults;
417         try {
418             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
419             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
420         } catch (InterruptedException | ExecutionException | TimeoutException e) {
421             LOG.warn("OLM power setup was not successful! Rendering and OLM will be rolled back.", e);
422             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
423                     powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
424                     "OLM power setup was not successful! Rendering and OLM will be rolled back.");
425             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
426                     this.olmService, powerSetupInputAtoZ));
427             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
428                     this.olmService, powerSetupInputZtoA));
429             return;
430         }
431
432         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
433                 this.olmService, powerSetupInputAtoZ));
434         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
435                 this.olmService, powerSetupInputZtoA));
436     }
437
438     private boolean isServiceActivated(String nodeId, String tpId) {
439         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
440         for (int i = 0; i < 3; i++) {
441             List<Measurements> measurements = getMeasurements(nodeId, tpId);
442             if ((measurements != null) && verifyPreFecBer(measurements)) {
443                 return true;
444             } else if (measurements == null) {
445                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
446                 return true;
447             } else {
448                 try {
449                     Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
450                 } catch (InterruptedException ex) {
451                     Thread.currentThread().interrupt();
452                 }
453             }
454         }
455         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
456         return false;
457     }
458
459     private List<Measurements> getMeasurements(String nodeId, String tp) {
460         GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder();
461         getPmIpBldr.setNodeId(nodeId);
462         getPmIpBldr.setGranularity(PmGranularity._15min);
463         ResourceIdentifierBuilder rsrcBldr = new ResourceIdentifierBuilder();
464         rsrcBldr.setResourceName(tp + "-OTU");
465         getPmIpBldr.setResourceIdentifier(rsrcBldr.build());
466         getPmIpBldr.setResourceType(ResourceTypeEnum.Interface);
467
468         try {
469             Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
470             RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
471             GetPmOutput getPmOutput = getPmRpcResult.getResult();
472             if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
473                 LOG.info("successfully finished calling OLM's get PM");
474                 return getPmOutput.getMeasurements(); // may return null
475             } else {
476                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
477             }
478
479         } catch (ExecutionException | InterruptedException e) {
480             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
481         }
482         return null;
483     }
484
485
486     private boolean verifyPreFecBer(List<Measurements> measurements) {
487         double preFecCorrectedErrors = Double.MIN_VALUE;
488         double fecUncorrectableBlocks = Double.MIN_VALUE;
489
490         for (Measurements measurement : measurements) {
491             if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
492                 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
493             }
494             if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
495                 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
496             }
497         }
498
499         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
500                 fecUncorrectableBlocks);
501
502         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
503             LOG.error("Data has uncorrectable errors, BER test failed");
504             return false;
505         } else {
506             double numOfBitsPerSecond = 112000000000d;
507             double threshold = 0.00002d;
508             double result = preFecCorrectedErrors / numOfBitsPerSecond;
509             LOG.info("PreFEC value is {}", Double.toString(result));
510             return result <= threshold;
511         }
512     }
513
514 }