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