Merge changes I74e9bee3,Ia1ad6f9c,Ic47363f6,I2bba2b18,I507097db, ...
[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.Map;
17 import java.util.Optional;
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 import org.opendaylight.mdsal.binding.api.DataBroker;
25 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
26 import org.opendaylight.mdsal.binding.api.ReadTransaction;
27 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
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.common.mapping.PortMapping;
32 import org.opendaylight.transportpce.common.service.ServiceTypes;
33 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
34 import org.opendaylight.transportpce.renderer.ServicePathInputData;
35 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
36 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.Action;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.OtnServicePathInput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownInputBuilder;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.RendererRpcResultSp;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.RendererRpcResultSpBuilder;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceDeleteInput;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceDeleteOutput;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceImplementationRequestInput;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceImplementationRequestOutput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.link._for.notif.ATerminationBuilder;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.link._for.notif.ZTerminationBuilder;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.renderer.rpc.result.sp.Link;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.renderer.rpc.result.sp.LinkBuilder;
61 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
62 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
63 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.PathDescription;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.ServicePathNotificationTypes;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTp;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.olm.get.pm.input.ResourceIdentifierBuilder;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.optical.renderer.nodes.Nodes;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.binding.Notification;
77 import org.opendaylight.yangtools.yang.common.RpcResult;
78 import org.opendaylight.yangtools.yang.common.Uint32;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82
83 public class RendererServiceOperationsImpl implements RendererServiceOperations {
84
85     private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
86             "Device rendering was not successful! Rendering will be rolled back.";
87     private static final String OLM_ROLL_BACK_MSG =
88             "OLM power setup was not successful! Rendering and OLM will be rolled back.";
89     private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
90     private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
91     private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
92     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
93     private static final String FAILED = "Failed";
94     private static final String OPERATION_FAILED = "Operation Failed";
95     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
96     private static final int NUMBER_OF_THREADS = 4;
97
98     private final DeviceRendererService deviceRenderer;
99     private final OtnDeviceRendererService otnDeviceRenderer;
100     private final TransportpceOlmService olmService;
101     private final DataBroker dataBroker;
102     private final NotificationPublishService notificationPublishService;
103     private final PortMapping portMapping;
104     private ListeningExecutorService executor;
105
106     public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
107             OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
108             DataBroker dataBroker, NotificationPublishService notificationPublishService, PortMapping portMapping) {
109         this.deviceRenderer = deviceRenderer;
110         this.otnDeviceRenderer = otnDeviceRenderer;
111         this.olmService = olmService;
112         this.dataBroker = dataBroker;
113         this.notificationPublishService = notificationPublishService;
114         this.portMapping = portMapping;
115         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
116     }
117
118     @Override
119     public ListenableFuture<ServiceImplementationRequestOutput>
120             serviceImplementation(ServiceImplementationRequestInput input) {
121         LOG.info("Calling service impl request {}", input.getServiceName());
122         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
123
124             @Override
125             public ServiceImplementationRequestOutput call() throws Exception {
126                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
127                         RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
128                 Uint32 serviceRate = getServiceRate(input);
129                 String serviceType = ServiceTypes.getServiceType(
130                     input.getServiceAEnd().getServiceFormat().getName(),
131                     serviceRate,
132                     (NodeTypes.Xpdr.equals(portMapping.getNode(input.getServiceAEnd().getNodeId())
133                         .getNodeInfo().getNodeType())
134                             && input.getServiceAEnd().getTxDirection() != null
135                             && input.getServiceAEnd().getTxDirection().getPort() != null
136                             && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null)
137                         ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
138                                 input.getServiceAEnd().getTxDirection().getPort().getPortName())
139                         : null);
140
141                 switch (serviceType) {
142                     case StringConstants.SERVICE_TYPE_100GE_T:
143                     case StringConstants.SERVICE_TYPE_400GE:
144                     case StringConstants.SERVICE_TYPE_OTU4:
145                     case StringConstants.SERVICE_TYPE_OTUC4:
146                         if (!manageServicePathCreation(input, serviceType)) {
147                             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
148                                 OPERATION_FAILED);
149                         }
150                         break;
151                     case StringConstants.SERVICE_TYPE_1GE:
152                     case StringConstants.SERVICE_TYPE_10GE:
153                     case StringConstants.SERVICE_TYPE_100GE_M:
154                     case StringConstants.SERVICE_TYPE_ODU4:
155                     case StringConstants.SERVICE_TYPE_ODUC4:
156                         if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
157                             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
158                                 OPERATION_FAILED);
159                         }
160                         break;
161                     default:
162                         LOG.error("unsupported service-type");
163                         return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
164                             OPERATION_FAILED);
165                 }
166                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
167                     OPERATION_SUCCESSFUL);
168             }
169         });
170     }
171
172     @Override
173     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
174         String serviceName = input.getServiceName();
175         LOG.info("Calling service delete request {}", serviceName);
176         return executor.submit(new Callable<ServiceDeleteOutput>() {
177
178             @Override
179             public ServiceDeleteOutput call() throws Exception {
180                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
181                         RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
182                 // Obtain path description
183                 Optional<
184                     org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
185                     .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
186                 if (pathDescriptionOpt.isEmpty()) {
187                     LOG.error("Unable to get path description for service {}!", serviceName);
188                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
189                             RpcStatusEx.Failed, "Unable to get path description for service");
190                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
191                             OPERATION_FAILED);
192                 }
193                 PathDescription pathDescription = pathDescriptionOpt.get();
194                 String serviceType = ServiceTypes.getServiceType(service.getServiceAEnd().getServiceFormat().getName(),
195                     service.getServiceAEnd().getServiceRate(), null);
196                 switch (serviceType) {
197                     case StringConstants.SERVICE_TYPE_100GE_T:
198                     case StringConstants.SERVICE_TYPE_400GE:
199                     case StringConstants.SERVICE_TYPE_OTU4:
200                     case StringConstants.SERVICE_TYPE_OTUC4:
201                         if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
202                             return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
203                                 OPERATION_FAILED);
204                         }
205                         break;
206                     case StringConstants.SERVICE_TYPE_1GE:
207                     case StringConstants.SERVICE_TYPE_10GE:
208                     case StringConstants.SERVICE_TYPE_100GE_M:
209                     case StringConstants.SERVICE_TYPE_ODU4:
210                     case StringConstants.SERVICE_TYPE_ODUC4:
211                         if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
212                             return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
213                                 OPERATION_FAILED);
214                         }
215                         break;
216                     default:
217                         LOG.error("unsupported service-type");
218                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
219                             OPERATION_FAILED);
220                 }
221                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
222             }
223         });
224     }
225
226     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
227         value = "UPM_UNCALLED_PRIVATE_METHOD",
228         justification = "call in call() method")
229     private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
230         if (input.getServiceAEnd() == null) {
231             LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
232             return Uint32.ZERO;
233         }
234         if (input.getServiceAEnd().getServiceRate() != null) {
235             return input.getServiceAEnd().getServiceRate();
236         }
237         Map<ServiceFormat, Map<String, Uint32>> formatRateMap  = Map.of(
238                 ServiceFormat.OTU, Map.of(
239                     "OTUCn", Uint32.valueOf(400),
240                     "OTU4", Uint32.valueOf(100),
241                     "OTU2", Uint32.valueOf(10),
242                     "OTU2e", Uint32.valueOf(10)),
243                 ServiceFormat.ODU, Map.of(
244                     "ODUCn",Uint32.valueOf(400),
245                     "ODU4", Uint32.valueOf(100),
246                     "ODU2", Uint32.valueOf(10),
247                     "ODU2e", Uint32.valueOf(10),
248                     "ODU0", Uint32.valueOf(1)));
249         if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
250             LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
251                 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
252             return Uint32.ZERO;
253         }
254         String serviceName =
255             ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
256                 ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
257                 : input.getServiceAEnd().getOduServiceRate().getSimpleName();
258         if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
259             LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
260                 input.getServiceName(), serviceName);
261             return Uint32.ZERO;
262         }
263         return formatRateMap.get(input.getServiceAEnd().getServiceFormat()).get(serviceName);
264     }
265
266     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
267             value = "UPM_UNCALLED_PRIVATE_METHOD",
268             justification = "call in call() method")
269     private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
270             throws InterruptedException, ExecutionException, TimeoutException {
271         LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
272         Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
273                 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
274         return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
275     }
276
277     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
278             value = "UPM_UNCALLED_PRIVATE_METHOD",
279             justification = "call in call() method")
280     private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
281         .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
282         InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
283             .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
284                 .child(ServicePaths.class, new ServicePathsKey(serviceName))
285                 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
286                     .service.path.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     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
300             value = "UPM_UNCALLED_PRIVATE_METHOD",
301             justification = "call in call() method")
302     private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
303             ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
304         LOG.info(RENDERING_DEVICES_A_Z_MSG);
305         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
306                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
307                 RENDERING_DEVICES_A_Z_MSG);
308         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
309                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
310                         ServicePathDirection.A_TO_Z));
311
312         LOG.info("Rendering devices Z-A");
313         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
314                 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
315                 RENDERING_DEVICES_Z_A_MSG);
316         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
317                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
318                         ServicePathDirection.Z_TO_A));
319         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
320                 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
321
322         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
323         try {
324             LOG.info("Waiting for A-Z and Z-A device renderers ...");
325             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
326         } catch (InterruptedException | ExecutionException | TimeoutException e) {
327             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
328             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
329                     servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
330                     DEVICE_RENDERING_ROLL_BACK_MSG);
331             //FIXME we can't do rollback here, because we don't have rendering results.
332             return renderingResults;
333         }
334
335         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
336                 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
337                 this.deviceRenderer));
338         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
339                 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
340                 this.deviceRenderer));
341         return renderingResults;
342     }
343
344     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
345         value = "UPM_UNCALLED_PRIVATE_METHOD",
346         justification = "call in call() method")
347     private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
348         OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA) {
349         LOG.info(RENDERING_DEVICES_A_Z_MSG);
350         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
351             otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
352             RENDERING_DEVICES_A_Z_MSG);
353         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
354             this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ));
355         LOG.info("Rendering devices Z-A");
356         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
357             otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
358             RENDERING_DEVICES_Z_A_MSG);
359         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
360             this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
361         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
362             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
363         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
364         try {
365             LOG.info("Waiting for A-Z and Z-A device renderers ...");
366             otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
367         } catch (InterruptedException | ExecutionException | TimeoutException e) {
368             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
369             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
370                 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
371                 DEVICE_RENDERING_ROLL_BACK_MSG);
372             //FIXME we can't do rollback here, because we don't have rendering results.
373             return otnRenderingResults;
374         }
375         for (int i = 0; i < otnRenderingResults.size(); i++) {
376             rollbackProcessor.addTask(new DeviceRenderingRollbackTask("DeviceTask n° " + i + 1,
377                 ! otnRenderingResults.get(i).isSuccess(), otnRenderingResults.get(i).getRenderedNodeInterfaces(),
378                 this.deviceRenderer));
379         }
380         return otnRenderingResults;
381     }
382
383     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
384             value = "UPM_UNCALLED_PRIVATE_METHOD",
385             justification = "call in call() method")
386     private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
387             ServicePowerSetupInput powerSetupInputZtoA) {
388         LOG.info("Olm power setup A-Z");
389         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
390                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
391         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
392                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
393
394         LOG.info("OLM power setup Z-A");
395         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
396                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
397         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
398                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
399         ListenableFuture<List<OLMRenderingResult>> olmFutures =
400                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
401
402         List<OLMRenderingResult> olmResults;
403         try {
404             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
405             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
406         } catch (InterruptedException | ExecutionException | TimeoutException e) {
407             LOG.warn(OLM_ROLL_BACK_MSG, e);
408             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
409                     powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
410                     OLM_ROLL_BACK_MSG);
411             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
412                     this.olmService, powerSetupInputAtoZ));
413             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
414                     this.olmService, powerSetupInputZtoA));
415             return;
416         }
417
418         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
419                 this.olmService, powerSetupInputAtoZ));
420         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
421                 this.olmService, powerSetupInputZtoA));
422     }
423
424     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
425             value = "UPM_UNCALLED_PRIVATE_METHOD",
426             justification = "call in call() method")
427     private boolean isServiceActivated(String nodeId, String tpId) {
428         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
429         for (int i = 0; i < 3; i++) {
430             List<Measurements> measurements = getMeasurements(nodeId, tpId);
431             if (measurements == null) {
432                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
433                 return true;
434             }
435             if (verifyPreFecBer(measurements)) {
436                 return true;
437             }
438             try {
439                 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
440             } catch (InterruptedException ex) {
441                 Thread.currentThread().interrupt();
442             }
443         }
444         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
445         return false;
446     }
447
448     private List<Measurements> getMeasurements(String nodeId, String tp) {
449         GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder()
450             .setNodeId(nodeId)
451             .setGranularity(PmGranularity._15min)
452             .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
453             .setResourceType(ResourceTypeEnum.Interface);
454
455         try {
456             Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
457             RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
458             GetPmOutput getPmOutput = getPmRpcResult.getResult();
459             if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
460                 LOG.info("successfully finished calling OLM's get PM");
461                 return getPmOutput.getMeasurements();
462                 // may return null
463             } else {
464                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
465             }
466
467         } catch (ExecutionException | InterruptedException e) {
468             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
469         }
470         return null;
471     }
472
473     private boolean verifyPreFecBer(List<Measurements> measurements) {
474         double preFecCorrectedErrors = Double.MIN_VALUE;
475         double fecUncorrectableBlocks = Double.MIN_VALUE;
476
477         for (Measurements measurement : measurements) {
478             switch (measurement.getPmparameterName()) {
479                 case "preFECCorrectedErrors":
480                     preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
481                     break;
482                 case "FECUncorrectableBlocks":
483                     fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
484                     break;
485                 default:
486                     break;
487             }
488         }
489
490         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
491                 fecUncorrectableBlocks);
492
493         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
494             LOG.error("Data has uncorrectable errors, BER test failed");
495             return false;
496         }
497
498         double numOfBitsPerSecond = 112000000000d;
499         double threshold = 0.00002d;
500         double result = preFecCorrectedErrors / numOfBitsPerSecond;
501         LOG.info("PreFEC value is {}", Double.toString(result));
502         return result <= threshold;
503     }
504
505     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
506         value = "UPM_UNCALLED_PRIVATE_METHOD",
507         justification = "call in call() method")
508     private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
509         ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
510             .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
511         ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
512             .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
513         // Rollback should be same for all conditions, so creating a new one
514         RollbackProcessor rollbackProcessor = new RollbackProcessor();
515         List<DeviceRenderingResult> renderingResults =
516             deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
517         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
518             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
519                 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
520             return false;
521         }
522         ServicePowerSetupInput olmPowerSetupInputAtoZ =
523             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
524         ServicePowerSetupInput olmPowerSetupInputZtoA =
525             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
526         olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
527         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
528             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
529                 input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
530             return false;
531         }
532         // run service activation test twice - once on source node and once on
533         // destination node
534         List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
535         if ((nodes == null) || (nodes.isEmpty())) {
536             return false;
537         }
538
539         Nodes sourceNode = nodes.get(0);
540         Nodes destNode = nodes.get(nodes.size() - 1);
541         String srcNetworkTp =
542             sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
543                 ? sourceNode.getDestTp()
544                 : sourceNode.getSrcTp();
545         String dstNetowrkTp =
546             destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
547                 ? destNode.getDestTp()
548                 : destNode.getSrcTp();
549
550         if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
551             || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
552             rollbackProcessor.rollbackAll();
553             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
554                 input.getServiceName(), RpcStatusEx.Failed,
555                 "Service activation test failed.");
556             return false;
557         }
558         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
559         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
560         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
561
562         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
563             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
564             notifLink, serviceType);
565         return true;
566     }
567
568     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
569         value = "UPM_UNCALLED_PRIVATE_METHOD",
570         justification = "call in call() method")
571     private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
572             throws InterruptedException {
573         ServicePathInputData servicePathInputDataAtoZ =
574             ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
575         ServicePathInputData servicePathInputDataZtoA =
576             ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
577         // OLM turn down power
578         try {
579             LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
580             sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
581                 RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
582             ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
583             // TODO add some flag rather than string
584             if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
585                 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
586                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
587                         "Service power turndown failed on A-to-Z path for service");
588                 return false;
589             }
590             LOG.debug("Turning down power on Z-to-A path");
591             sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
592                     "Turning down power on Z-to-A path");
593             ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
594             // TODO add some flag rather than string
595             if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
596                 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
597                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
598                         "Service power turndown failed on Z-to-A path for service");
599                 return false;
600             }
601         } catch (InterruptedException | ExecutionException | TimeoutException e) {
602             LOG.error("Error while turning down power!", e);
603             return false;
604         }
605         // delete service path with renderer
606         LOG.info("Deleting service path via renderer");
607         sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
608                 "Deleting service path via renderer");
609         RollbackProcessor rollbackProcessor = new RollbackProcessor();
610         List<DeviceRenderingResult> renderingResults =
611             deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
612         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
613         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
614         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
615
616         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
617                 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, serviceType);
618         return true;
619     }
620
621     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
622         value = "UPM_UNCALLED_PRIVATE_METHOD",
623         justification = "call in call() method")
624     private boolean manageOtnServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
625             Uint32 serviceRate) {
626         // This is A-Z side
627         OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
628             .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
629                 input.getServiceAEnd().getServiceFormat().getName(),
630                 serviceRate,
631                 input.getPathDescription(), true);
632         // This is Z-A side
633         OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
634             .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
635                 input.getServiceZEnd().getServiceFormat().getName(),
636                 serviceRate,
637                 input.getPathDescription(), false);
638         // Rollback should be same for all conditions, so creating a new one
639         RollbackProcessor rollbackProcessor = new RollbackProcessor();
640         List<OtnDeviceRenderingResult> renderingResults =
641             otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA);
642         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
643             rollbackProcessor.rollbackAll();
644             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
645                 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
646             return false;
647         }
648         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
649         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
650         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
651
652         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
653             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
654             notifLink, serviceType);
655         return true;
656     }
657
658     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
659         value = "UPM_UNCALLED_PRIVATE_METHOD",
660         justification = "call in call() method")
661     private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
662             Services service, String serviceType) {
663         // This is A-Z side
664         OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
665             .rendererCreateOtnServiceInput(serviceName, Action.Delete,
666                 service.getServiceAEnd().getServiceFormat().getName(),
667                 service.getServiceAEnd().getServiceRate(),
668                 pathDescription, true);
669         // This is Z-A side
670         OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
671             .rendererCreateOtnServiceInput(serviceName, Action.Delete,
672                 service.getServiceZEnd().getServiceFormat().getName(),
673                 service.getServiceAEnd().getServiceRate(),
674                 pathDescription, false);
675         LOG.info("Deleting otn-service path {} via renderer", serviceName);
676         sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
677                 "Deleting otn-service path via renderer");
678
679         RollbackProcessor rollbackProcessor = new RollbackProcessor();
680         List<OtnDeviceRenderingResult> renderingResults =
681             otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA);
682
683         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
684         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
685         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
686
687         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
688                 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, serviceType);
689         return true;
690     }
691
692     /**
693      * Send renderer notification.
694      * @param servicePathNotificationTypes ServicePathNotificationTypes
695      * @param serviceName String
696      * @param rpcStatusEx RpcStatusEx
697      * @param message String
698      */
699     private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
700             RpcStatusEx rpcStatusEx, String message) {
701         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
702                 null, null, null);
703         send(notification);
704     }
705
706     /**
707      * Send renderer notification with path description information.
708      * @param servicePathNotificationTypes ServicePathNotificationTypes
709      * @param serviceName String
710      * @param rpcStatusEx RpcStatusEx
711      * @param message String
712      * @param pathDescription PathDescription
713      */
714     private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
715             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
716             Link notifLink, String serviceType) {
717         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
718                 pathDescription, notifLink, serviceType);
719         send(notification);
720     }
721
722     /**
723      * Build notification containing path description information.
724      * @param servicePathNotificationTypes ServicePathNotificationTypes
725      * @param serviceName String
726      * @param rpcStatusEx RpcStatusEx
727      * @param message String
728      * @param pathDescription PathDescription
729      * @return notification with RendererRpcResultSp type.
730      */
731     private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
732             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
733             Link notifLink, String serviceType) {
734         RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
735                 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
736                 .setStatusMessage(message)
737                 .setServiceType(serviceType);
738         if (pathDescription != null) {
739             builder.setAToZDirection(pathDescription.getAToZDirection())
740                 .setZToADirection(pathDescription.getZToADirection());
741         }
742         if (notifLink != null) {
743             builder.setLink(notifLink);
744         }
745         return builder.build();
746     }
747
748     /**
749      * Send renderer notification.
750      * @param notification Notification
751      */
752     private void send(Notification notification) {
753         try {
754             LOG.info("Sending notification {}", notification);
755             notificationPublishService.putNotification(notification);
756         } catch (InterruptedException e) {
757             LOG.info("notification offer rejected: ", e);
758             Thread.currentThread().interrupt();
759         }
760     }
761
762     private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
763         if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
764             return null;
765         }
766         return new LinkBuilder()
767                 .setATermination(new ATerminationBuilder()
768                     .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
769                     .setTpId(otnLinkTerminationPoints.get(0).getTpId())
770                     .build())
771                 .setZTermination(new ZTerminationBuilder()
772                     .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
773                     .setTpId(otnLinkTerminationPoints.get(1).getTpId())
774                     .build())
775                 .build();
776     }
777 }