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