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