Update release in docs/conf.yaml
[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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Optional;
19 import java.util.Set;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Executors;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import java.util.stream.Collectors;
26 import org.opendaylight.mdsal.binding.api.DataBroker;
27 import org.opendaylight.mdsal.binding.api.RpcService;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.transportpce.common.ResponseCodes;
30 import org.opendaylight.transportpce.common.StringConstants;
31 import org.opendaylight.transportpce.common.Timeouts;
32 import org.opendaylight.transportpce.common.mapping.PortMapping;
33 import org.opendaylight.transportpce.common.service.ServiceTypes;
34 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
35 import org.opendaylight.transportpce.renderer.ServicePathInputData;
36 import org.opendaylight.transportpce.renderer.provisiondevice.notification.Notification;
37 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.NetworkDeviceRenderingRollbackTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
42 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
43 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerTurnDownTask;
44 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
45 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
46 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackResultMessage;
47 import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.History;
48 import org.opendaylight.transportpce.renderer.provisiondevice.transaction.history.TransactionHistory;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630.OtnLinkType;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPm;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetup;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndown;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
61 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
62 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
63 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
64 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
65 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
66 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
67 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
68 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
69 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
70 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.Services;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.PathDescription;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
76 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
77 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.PmGranularity;
78 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.link.tp.LinkTp;
79 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.olm.get.pm.input.ResourceIdentifierBuilder;
80 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.optical.renderer.nodes.Nodes;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
82 import org.opendaylight.yangtools.yang.common.Uint32;
83 import org.osgi.service.component.annotations.Activate;
84 import org.osgi.service.component.annotations.Component;
85 import org.osgi.service.component.annotations.Reference;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89
90 @Component(immediate = true)
91 public class RendererServiceOperationsImpl implements RendererServiceOperations {
92
93     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
94     private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
95             "Device rendering was not successful! Rendering will be rolled back.";
96     private static final String OLM_ROLL_BACK_MSG =
97             "OLM power setup was not successful! Rendering and OLM will be rolled back.";
98     private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
99     private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
100     private static final String ATOZPATH = "A-to-Z";
101     private static final String ZTOAPATH = "Z-to-A";
102     private static final String OPERATION_FAILED = "Operation Failed";
103     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
104     private static final int NUMBER_OF_THREADS = 4;
105
106     private final DeviceRendererService deviceRenderer;
107     private final OtnDeviceRendererService otnDeviceRenderer;
108     private final DataBroker dataBroker;
109     private final Notification notification;
110     private final PortMapping portMapping;
111     private final RpcService rpcService;
112     private ListeningExecutorService executor;
113
114     @Activate
115     public RendererServiceOperationsImpl(@Reference DeviceRendererService deviceRenderer,
116             @Reference OtnDeviceRendererService otnDeviceRenderer,
117             @Reference DataBroker dataBroker,
118             @Reference Notification notification,
119             @Reference PortMapping portMapping,
120             @Reference RpcService rpcService) {
121         this.deviceRenderer = deviceRenderer;
122         this.otnDeviceRenderer = otnDeviceRenderer;
123         this.dataBroker = dataBroker;
124         this.notification = notification;
125         this.portMapping = portMapping;
126         this.rpcService = rpcService;
127         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
128         LOG.debug("RendererServiceOperationsImpl instantiated");
129     }
130
131     @Override
132     public ListenableFuture<ServiceImplementationRequestOutput>
133             serviceImplementation(ServiceImplementationRequestInput input, boolean isTempService) {
134         LOG.info("Calling service impl request {}", input.getServiceName());
135         LOG.debug("Check if it is temp-service {}", isTempService);
136         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
137
138             @Override
139             public ServiceImplementationRequestOutput call() throws Exception {
140                 sendNotifications(
141                     ServicePathNotificationTypes.ServiceImplementationRequest,
142                     input.getServiceName(),
143                     RpcStatusEx.Pending,
144                     "Service compliant, submitting service implementation Request ...");
145                 Uint32 serviceRate = getServiceRate(input);
146                 LOG.info("Using {}G rate", serviceRate);
147                 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221
148                         .network.Nodes mappingNode =
149                     portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
150                         ? portMapping.getNode(input.getServiceAEnd().getNodeId())
151                         : null;
152                 String serviceType = ServiceTypes.getServiceType(
153                     input.getServiceAEnd().getServiceFormat().getName(),
154                     serviceRate,
155                     mappingNode != null
156                         && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
157                             && input.getServiceAEnd().getTxDirection() != null
158                             && input.getServiceAEnd().getTxDirection().getPort() != null
159                             && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
160                         ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
161                                 input.getServiceAEnd().getTxDirection().getPort().getPortName())
162                         : null);
163                 //TODO a Map might be more indicated here
164                 switch (serviceType) {
165                     case StringConstants.SERVICE_TYPE_100GE_T:
166                     case StringConstants.SERVICE_TYPE_400GE:
167                     case StringConstants.SERVICE_TYPE_OTU4:
168                     case StringConstants.SERVICE_TYPE_OTUC2:
169                     case StringConstants.SERVICE_TYPE_OTUC3:
170                     case StringConstants.SERVICE_TYPE_OTUC4:
171                         LOG.debug("Check temp service {}", isTempService);
172                         if (!manageServicePathCreation(input, serviceType, isTempService)) {
173                             return ModelMappingUtils
174                                 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
175                         }
176                         break;
177                     case StringConstants.SERVICE_TYPE_1GE:
178                     case StringConstants.SERVICE_TYPE_10GE:
179                     case StringConstants.SERVICE_TYPE_100GE_M:
180                     case StringConstants.SERVICE_TYPE_100GE_S:
181                     case StringConstants.SERVICE_TYPE_ODU4:
182                     case StringConstants.SERVICE_TYPE_ODUC2:
183                     case StringConstants.SERVICE_TYPE_ODUC3:
184                     case StringConstants.SERVICE_TYPE_ODUC4:
185                         if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
186                             return ModelMappingUtils
187                                 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
188                         }
189                         break;
190                     default:
191                         LOG.error("unsupported service-type");
192                         return ModelMappingUtils
193                             .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
194                 }
195                 return ModelMappingUtils
196                     .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
197             }
198         });
199     }
200
201     @Override
202     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
203         String serviceName = input.getServiceName();
204         LOG.info("Calling service delete request {}", serviceName);
205         return executor.submit(new Callable<ServiceDeleteOutput>() {
206
207             @Override
208             public ServiceDeleteOutput call() throws Exception {
209                 sendNotifications(
210                     ServicePathNotificationTypes.ServiceDelete,
211                     serviceName,
212                     RpcStatusEx.Pending,
213                     "Service compliant, submitting service delete Request ...");
214                 // Obtain path description
215                 Optional<
216                     org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
217                         .service.path.PathDescription> pathDescriptionOpt =
218                     getPathDescriptionFromDatastore(serviceName);
219                 if (pathDescriptionOpt.isEmpty()) {
220                     LOG.error("Unable to get path description for service {}!", serviceName);
221                     sendNotifications(
222                         ServicePathNotificationTypes.ServiceDelete,
223                         serviceName,
224                         RpcStatusEx.Failed,
225                         "Unable to get path description for service");
226                     return ModelMappingUtils
227                         .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
228                 }
229                 PathDescription pathDescription = pathDescriptionOpt.orElseThrow();
230                 String serviceType =
231                     ServiceTypes.getServiceType(
232                         service.getServiceAEnd().getServiceFormat().getName(),
233                         service.getServiceAEnd().getServiceRate(),
234                         service.getServiceAEnd().getTxDirection() == null
235                                 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
236                                     .getPort() == null
237                                 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
238                                     .getPort().getPortName() == null
239                             ? null
240                             : portMapping.getMapping(
241                                     service.getServiceAEnd().getNodeId().getValue(),
242                                     service.getServiceAEnd().getTxDirection().values().stream().findFirst()
243                                         .orElseThrow().getPort().getPortName()));
244                 switch (serviceType) {
245                     case StringConstants.SERVICE_TYPE_100GE_T:
246                     case StringConstants.SERVICE_TYPE_400GE:
247                     case StringConstants.SERVICE_TYPE_OTU4:
248                     case StringConstants.SERVICE_TYPE_OTUC2:
249                     case StringConstants.SERVICE_TYPE_OTUC3:
250                     case StringConstants.SERVICE_TYPE_OTUC4:
251                         if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
252                             return ModelMappingUtils
253                                 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
254                         }
255                         break;
256                     case StringConstants.SERVICE_TYPE_1GE:
257                     case StringConstants.SERVICE_TYPE_10GE:
258                     case StringConstants.SERVICE_TYPE_100GE_M:
259                     case StringConstants.SERVICE_TYPE_100GE_S:
260                     case StringConstants.SERVICE_TYPE_ODU4:
261                     case StringConstants.SERVICE_TYPE_ODUC2:
262                     case StringConstants.SERVICE_TYPE_ODUC3:
263                     case StringConstants.SERVICE_TYPE_ODUC4:
264                         if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
265                             return ModelMappingUtils
266                                 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
267                         }
268                         break;
269                     default:
270                         LOG.error("unsupported service-type");
271                         return ModelMappingUtils
272                             .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
273                 }
274                 return ModelMappingUtils
275                     .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
276             }
277         });
278     }
279
280     @SuppressFBWarnings(
281         value = "UPM_UNCALLED_PRIVATE_METHOD",
282         justification = "call in call() method")
283     private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
284         if (input.getServiceAEnd() == null) {
285             LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
286             return Uint32.ZERO;
287         }
288         if (input.getServiceAEnd().getServiceRate() != null) {
289             return input.getServiceAEnd().getServiceRate();
290         }
291         LOG.warn("Input should have rate if you are using 200 or 300G");
292         // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
293         Map<ServiceFormat, Map<String, Uint32>> formatRateMap  = Map.of(
294                 ServiceFormat.OTU, Map.of(
295                     "OTUCn", Uint32.valueOf(400),
296                     "OTU4", Uint32.valueOf(100),
297                     "OTU2", Uint32.valueOf(10),
298                     "OTU2e", Uint32.valueOf(10)),
299                 ServiceFormat.ODU, Map.of(
300                     "ODUCn",Uint32.valueOf(400),
301                     "ODU4", Uint32.valueOf(100),
302                     "ODU2", Uint32.valueOf(10),
303                     "ODU2e", Uint32.valueOf(10),
304                     "ODU0", Uint32.valueOf(1)));
305         if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
306             LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
307                 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
308             return Uint32.ZERO;
309         }
310         String serviceName =
311             ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
312                 ? input.getServiceAEnd().getOtuServiceRate().toString().split("\\{")[0]
313                 : input.getServiceAEnd().getOduServiceRate().toString().split("\\{")[0];
314         if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
315             LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
316                 input.getServiceName(), serviceName);
317             return Uint32.ZERO;
318         }
319         return formatRateMap
320             .get(input.getServiceAEnd().getServiceFormat())
321             .get(serviceName);
322     }
323
324     @SuppressFBWarnings(
325             value = "UPM_UNCALLED_PRIVATE_METHOD",
326             justification = "call in call() method")
327     private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
328             .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
329         InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
330                 .service.path.PathDescription> pathDescriptionIID =
331             InstanceIdentifier.create(ServicePathList.class)
332                 .child(ServicePaths.class, new ServicePathsKey(serviceName))
333                 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
334                     .service.path.PathDescription.class);
335         try {
336             LOG.debug("Getting path description for service {}", serviceName);
337             return this.dataBroker.newReadOnlyTransaction()
338                     .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
339                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
340         } catch (InterruptedException | ExecutionException | TimeoutException e) {
341             LOG.warn("Exception while getting path description from datastore {} for service {}!",
342                     pathDescriptionIID, serviceName, e);
343             return Optional.empty();
344         }
345     }
346
347     @SuppressFBWarnings(
348             value = "UPM_UNCALLED_PRIVATE_METHOD",
349             justification = "call in call() method")
350     private List<DeviceRenderingResult> deviceRendering(
351             RollbackProcessor rollbackProcessor,
352             ServicePathInputData servicePathDataAtoZ,
353             ServicePathInputData servicePathDataZtoA) {
354
355         //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
356         //     Do notifications & LOG.info deserve this ?
357         LOG.info(RENDERING_DEVICES_A_Z_MSG);
358         sendNotifications(
359             ServicePathNotificationTypes.ServiceImplementationRequest,
360             servicePathDataAtoZ.getServicePathInput().getServiceName(),
361             RpcStatusEx.Pending,
362             RENDERING_DEVICES_A_Z_MSG);
363
364         History transactionHistory = new TransactionHistory();
365         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
366             this.executor.submit(
367                 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z,
368                         transactionHistory));
369
370         LOG.info(RENDERING_DEVICES_Z_A_MSG);
371         sendNotifications(
372             ServicePathNotificationTypes.ServiceImplementationRequest,
373             servicePathDataZtoA.getServicePathInput().getServiceName(),
374             RpcStatusEx.Pending,
375             RENDERING_DEVICES_Z_A_MSG);
376         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
377             this.executor.submit(
378                 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A,
379                         transactionHistory));
380
381         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
382             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
383
384         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
385         try {
386             LOG.info("Waiting for A-Z and Z-A device renderers ...");
387             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
388         } catch (InterruptedException | ExecutionException | TimeoutException e) {
389             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
390             sendNotifications(
391                 ServicePathNotificationTypes.ServiceImplementationRequest,
392                 servicePathDataAtoZ.getServicePathInput().getServiceName(),
393                 RpcStatusEx.Pending,
394                 DEVICE_RENDERING_ROLL_BACK_MSG);
395             //FIXME we can't do rollback here, because we don't have rendering results.
396             return renderingResults;
397         }
398
399         rollbackProcessor.addTask(
400             new NetworkDeviceRenderingRollbackTask(
401                 "RollbackTransactionHistoryTask",
402                 transactionHistory,
403                 ! (renderingResults.get(0).isSuccess() && renderingResults.get(1).isSuccess()),
404                 deviceRenderer,
405                 new RollbackResultMessage()
406             )
407         );
408
409         return renderingResults;
410     }
411
412     @SuppressFBWarnings(
413         value = "UPM_UNCALLED_PRIVATE_METHOD",
414         justification = "call in call() method")
415     private List<OtnDeviceRenderingResult> otnDeviceRendering(
416             RollbackProcessor rollbackProcessor,
417             OtnServicePathInput otnServicePathAtoZ,
418             OtnServicePathInput otnServicePathZtoA,
419             String serviceType) {
420
421         //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
422         //     Do notifications & LOG.info deserve this ?
423         LOG.info(RENDERING_DEVICES_A_Z_MSG);
424         sendNotifications(
425             ServicePathNotificationTypes.ServiceImplementationRequest,
426             otnServicePathAtoZ.getServiceName(),
427             RpcStatusEx.Pending,
428             RENDERING_DEVICES_A_Z_MSG);
429         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
430             this.executor.submit(
431                 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
432
433         LOG.info(RENDERING_DEVICES_Z_A_MSG);
434         sendNotifications(
435             ServicePathNotificationTypes.ServiceImplementationRequest,
436             otnServicePathZtoA.getServiceName(),
437             RpcStatusEx.Pending,
438             RENDERING_DEVICES_Z_A_MSG);
439         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
440             this.executor.submit(
441                 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
442
443         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
444             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
445         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
446         try {
447             LOG.info("Waiting for A-Z and Z-A device renderers ...");
448             otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
449         } catch (InterruptedException | ExecutionException | TimeoutException e) {
450             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
451             sendNotifications(
452                 ServicePathNotificationTypes.ServiceImplementationRequest,
453                 otnServicePathAtoZ.getServiceName(),
454                 RpcStatusEx.Pending,
455                 DEVICE_RENDERING_ROLL_BACK_MSG);
456             //FIXME we can't do rollback here, because we don't have rendering results.
457             return otnRenderingResults;
458         }
459         for (int i = 0; i < otnRenderingResults.size(); i++) {
460             rollbackProcessor.addTask(
461                 new DeviceRenderingRollbackTask(
462                     "DeviceTask n° " + i + 1,
463                     ! otnRenderingResults.get(i).isSuccess(),
464                     otnRenderingResults.get(i).getRenderedNodeInterfaces(),
465                     this.deviceRenderer));
466         }
467         return otnRenderingResults;
468     }
469
470     @SuppressFBWarnings(
471             value = "UPM_UNCALLED_PRIVATE_METHOD",
472             justification = "call in call() method")
473     private void olmPowerSetup(
474             RollbackProcessor rollbackProcessor,
475             ServicePowerSetupInput powerSetupInputAtoZ,
476             ServicePowerSetupInput powerSetupInputZtoA, boolean isTempService) {
477
478         //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
479         //     Do notifications & LOG.info deserve this ?
480         //TODO use constants for LOG.info & notifications common messages
481         // if the service create is a temp-service, OLM will be skipped
482         if (isTempService) {
483             LOG.info("For temp-service create OLM is not computed and skipped");
484             return;
485         }
486         LOG.info("Olm power setup A-Z");
487         sendNotifications(
488                 ServicePathNotificationTypes.ServiceImplementationRequest,
489                 powerSetupInputAtoZ.getServiceName(),
490                 RpcStatusEx.Pending,
491                 "Olm power setup A-Z");
492         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
493                 this.executor.submit(
494                     new OlmPowerSetupTask(rpcService.getRpc(ServicePowerSetup.class), powerSetupInputAtoZ));
495
496         LOG.info("OLM power setup Z-A");
497         sendNotifications(
498                 ServicePathNotificationTypes.ServiceImplementationRequest,
499                 powerSetupInputAtoZ.getServiceName(),
500                 RpcStatusEx.Pending,
501                 "Olm power setup Z-A");
502         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
503                 this.executor.submit(
504                     new OlmPowerSetupTask(rpcService.getRpc(ServicePowerSetup.class), powerSetupInputZtoA));
505         ListenableFuture<List<OLMRenderingResult>> olmFutures =
506                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
507
508         List<OLMRenderingResult> olmResults;
509         try {
510             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
511             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
512         } catch (InterruptedException | ExecutionException | TimeoutException e) {
513             LOG.warn(OLM_ROLL_BACK_MSG, e);
514             sendNotifications(
515                     ServicePathNotificationTypes.ServiceImplementationRequest,
516                     powerSetupInputAtoZ.getServiceName(),
517                     RpcStatusEx.Pending,
518                     OLM_ROLL_BACK_MSG);
519             rollbackProcessor.addTask(
520                     new OlmPowerSetupRollbackTask("AtoZOLMTask", true, rpcService.getRpc(ServicePowerTurndown.class),
521                         powerSetupInputAtoZ));
522             rollbackProcessor.addTask(
523                     new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, rpcService.getRpc(ServicePowerTurndown.class),
524                         powerSetupInputZtoA));
525             return;
526         }
527         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask(
528                 "AtoZOLMTask", !olmResults.get(0).isSuccess(), rpcService.getRpc(ServicePowerTurndown.class),
529                 powerSetupInputAtoZ));
530         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask(
531                 "ZtoAOLMTask", !olmResults.get(1).isSuccess(), rpcService.getRpc(ServicePowerTurndown.class),
532                 powerSetupInputZtoA));
533     }
534
535     @SuppressFBWarnings(
536             value = "UPM_UNCALLED_PRIVATE_METHOD",
537             justification = "call in call() method")
538     private boolean isServiceActivated(String nodeId, String tpId) {
539         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
540         if (!NodeTypes.Xpdr.equals(portMapping.getNode(nodeId).getNodeInfo().getNodeType())) {
541             LOG.info("Device {} is not xponder, can't verify PreFEC", nodeId);
542             return true;
543         }
544         for (int i = 0; i < 3; i++) {
545             List<Measurements> measurements = getMeasurements(nodeId, tpId);
546             if (measurements == null) {
547                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
548                 return true;
549             }
550             if (verifyPreFecBer(measurements)) {
551                 return true;
552             }
553             try {
554                 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
555             } catch (InterruptedException ex) {
556                 Thread.currentThread().interrupt();
557             }
558         }
559         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
560         return false;
561     }
562
563     private List<Measurements> getMeasurements(String nodeId, String tp) {
564         try {
565             GetPmOutput getPmOutput = rpcService.getRpc(GetPm.class).invoke(
566                         new GetPmInputBuilder()
567                             .setNodeId(nodeId)
568                             .setGranularity(PmGranularity._15min)
569                             .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
570                             .setResourceType(ResourceTypeEnum.Interface)
571                             .build())
572                     .get()
573                     .getResult();
574             if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
575                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
576             } else {
577                 LOG.info("successfully finished calling OLM's get PM");
578                 return getPmOutput.getMeasurements();
579                 // may return null
580             }
581
582         } catch (ExecutionException | InterruptedException e) {
583             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
584         }
585         return null;
586     }
587
588     private boolean verifyPreFecBer(List<Measurements> measurements) {
589         double preFecCorrectedErrors = Double.MIN_VALUE;
590         double fecUncorrectableBlocks = Double.MIN_VALUE;
591
592         for (Measurements measurement : measurements) {
593             switch (measurement.getPmparameterName()) {
594                 case "preFECCorrectedErrors":
595                     preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
596                     break;
597                 case "FECUncorrectableBlocks":
598                     fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
599                     break;
600                 default:
601                     break;
602             }
603         }
604
605         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
606                 preFecCorrectedErrors, fecUncorrectableBlocks);
607
608         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
609             LOG.error("Data has uncorrectable errors, BER test failed");
610             return false;
611         }
612
613         double numOfBitsPerSecond = 112000000000d;
614         double threshold = 0.00002d;
615         double result = preFecCorrectedErrors / numOfBitsPerSecond;
616         LOG.info("PreFEC value is {}", Double.toString(result));
617         return result <= threshold;
618     }
619
620     @SuppressFBWarnings(
621         value = "UPM_UNCALLED_PRIVATE_METHOD",
622         justification = "call in call() method")
623     private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
624                                               boolean isTempService) {
625         ServicePathInputData servicePathInputDataAtoZ =
626             ModelMappingUtils
627                 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
628         ServicePathInputData servicePathInputDataZtoA =
629             ModelMappingUtils
630                 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
631         // Rollback should be same for all conditions, so creating a new one
632         RollbackProcessor rollbackProcessor = new RollbackProcessor();
633         List<DeviceRenderingResult> renderingResults =
634             deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
635         if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
636             sendNotifications(
637                 ServicePathNotificationTypes.ServiceImplementationRequest,
638                 input.getServiceName(),
639                 RpcStatusEx.Failed,
640                 DEVICE_RENDERING_ROLL_BACK_MSG);
641             return false;
642         }
643         olmPowerSetup(
644             rollbackProcessor,
645             //olmPowerSetupInputAtoZ,
646             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
647             //olmPowerSetupInputZtoA
648             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input), isTempService);
649         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
650             sendNotifications(
651                 ServicePathNotificationTypes.ServiceImplementationRequest,
652                 input.getServiceName(),
653                 RpcStatusEx.Failed,
654                 OLM_ROLL_BACK_MSG);
655             return false;
656         }
657         // run service activation test twice - once on source node and once on
658         // destination node
659         List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
660         if ((nodes == null) || (nodes.isEmpty())) {
661             return false;
662         }
663
664         Nodes sourceNode = nodes.get(0);
665         Nodes destNode = nodes.get(nodes.size() - 1);
666         String srcNetworkTp =
667             sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
668                 ? sourceNode.getDestTp()
669                 : sourceNode.getSrcTp();
670         String dstNetowrkTp =
671             destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
672                 ? destNode.getDestTp()
673                 : destNode.getSrcTp();
674
675         if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
676                 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
677             rollbackProcessor.rollbackAll();
678             sendNotifications(
679                 ServicePathNotificationTypes.ServiceImplementationRequest,
680                 input.getServiceName(),
681                 RpcStatusEx.Failed,
682                 "Service activation test failed.");
683             return false;
684         }
685         sendNotificationsWithPathDescription(
686             ServicePathNotificationTypes.ServiceImplementationRequest,
687             input.getServiceName(),
688             RpcStatusEx.Successful,
689             OPERATION_SUCCESSFUL,
690             input.getPathDescription(),
691             createLinkForNotif(
692                 renderingResults.stream()
693                     .flatMap(rr -> rr.getOtnLinkTps().stream())
694                     .collect(Collectors.toList())),
695             null,
696             serviceType);
697         return true;
698     }
699
700     @SuppressFBWarnings(
701         value = "UPM_UNCALLED_PRIVATE_METHOD",
702         justification = "call in call() method")
703     private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
704             throws InterruptedException {
705         ServicePathInputData servicePathInputDataAtoZ =
706             ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
707         ServicePathInputData servicePathInputDataZtoA =
708             ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
709
710         ListenableFuture<OLMRenderingResult> olmPowerTurnDownFutureAtoZ = this.executor.submit(
711                 new OlmPowerTurnDownTask(serviceName, ATOZPATH, servicePathInputDataAtoZ, notification, rpcService));
712
713         ListenableFuture<OLMRenderingResult> olmPowerTurnDownFutureZtoA = this.executor.submit(
714                 new OlmPowerTurnDownTask(serviceName, ZTOAPATH, servicePathInputDataZtoA, notification, rpcService));
715
716         ListenableFuture<List<OLMRenderingResult>> olmPowerTurnDownFutures =
717             Futures.allAsList(olmPowerTurnDownFutureAtoZ, olmPowerTurnDownFutureZtoA);
718
719         List<OLMRenderingResult> olmRenderingResults;
720         // OLM turn down power
721         try {
722             LOG.info("Waiting for A-Z and Z-A OLM power turn down ...");
723             olmRenderingResults = olmPowerTurnDownFutures.get(
724                 Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS
725             );
726         } catch (InterruptedException | ExecutionException | TimeoutException e) {
727             LOG.error("Error while turning down power!", e);
728             return false;
729         }
730         if (!olmRenderingResults.get(0).isSuccess() || !olmRenderingResults.get(1).isSuccess()) {
731             LOG.error("Error while turning down power!");
732             return false;
733         }
734         LOG.info("OLM power successfully turned down!");
735         // delete service path with renderer
736         LOG.info("Deleting service path via renderer");
737         sendNotifications(
738             ServicePathNotificationTypes.ServiceDelete,
739             serviceName,
740             RpcStatusEx.Pending,
741             "Deleting service path via renderer");
742         sendNotificationsWithPathDescription(
743             ServicePathNotificationTypes.ServiceDelete,
744             serviceName,
745             RpcStatusEx.Successful,
746             OPERATION_SUCCESSFUL,
747             pathDescription,
748             createLinkForNotif(
749                 deviceRendering(
750                         new RollbackProcessor(),
751                         servicePathInputDataAtoZ,
752                         servicePathInputDataZtoA)
753                     .stream()
754                     .flatMap(rr -> rr.getOtnLinkTps().stream())
755                     .collect(Collectors.toList())),
756             null,
757             serviceType);
758         return true;
759     }
760
761     @SuppressFBWarnings(
762         value = "UPM_UNCALLED_PRIVATE_METHOD",
763         justification = "call in call() method")
764     private boolean manageOtnServicePathCreation(
765             ServiceImplementationRequestInput input,
766             String serviceType,
767             Uint32 serviceRate) {
768         // Rollback should be same for all conditions, so creating a new one
769         RollbackProcessor rollbackProcessor = new RollbackProcessor();
770         List<OtnDeviceRenderingResult> renderingResults =
771             otnDeviceRendering(
772                 rollbackProcessor,
773                 // This is A-Z side
774                 ModelMappingUtils
775                     .rendererCreateOtnServiceInput(
776                         input.getServiceName(),
777                         Action.Create,
778                         input.getServiceAEnd().getServiceFormat().getName(),
779                         serviceRate,
780                         input.getPathDescription(),
781                         true),
782                 // This is Z-A side
783                 ModelMappingUtils
784                     .rendererCreateOtnServiceInput(
785                         input.getServiceName(),
786                         Action.Create,
787                         input.getServiceZEnd().getServiceFormat().getName(),
788                         serviceRate,
789                         input.getPathDescription(),
790                         false),
791                 serviceType);
792         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
793             rollbackProcessor.rollbackAll();
794             sendNotifications(
795                 ServicePathNotificationTypes.ServiceImplementationRequest,
796                 input.getServiceName(),
797                 RpcStatusEx.Failed,
798                 DEVICE_RENDERING_ROLL_BACK_MSG);
799             return false;
800         }
801         sendNotificationsWithPathDescription(
802             ServicePathNotificationTypes.ServiceImplementationRequest,
803             input.getServiceName(),
804             RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
805             input.getPathDescription(),
806             createLinkForNotif(
807                 renderingResults.stream()
808                     .flatMap(rr -> rr.getOtnLinkTps().stream())
809                     .collect(Collectors.toList())),
810             getSupportedLinks(
811                 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
812                 serviceType),
813             serviceType);
814         return true;
815     }
816
817     @SuppressFBWarnings(
818         value = "UPM_UNCALLED_PRIVATE_METHOD",
819         justification = "call in call() method")
820     private boolean manageOtnServicePathDeletion(
821             String serviceName,
822             PathDescription pathDescription,
823             Services service,
824             String serviceType) {
825         LOG.info("Deleting otn-service path {} via renderer", serviceName);
826         sendNotifications(
827                 ServicePathNotificationTypes.ServiceDelete,
828                 serviceName,
829                 RpcStatusEx.Pending,
830                 "Deleting otn-service path via renderer");
831         List<OtnDeviceRenderingResult> renderingResults =
832             otnDeviceRendering(
833                 new RollbackProcessor(),
834                 // This is A-Z side
835                 ModelMappingUtils
836                     .rendererCreateOtnServiceInput(
837                         serviceName,
838                         Action.Delete,
839                         service.getServiceAEnd().getServiceFormat().getName(),
840                         service.getServiceAEnd().getServiceRate(),
841                         pathDescription,
842                         true),
843                 // This is Z-A side
844                 ModelMappingUtils
845                     .rendererCreateOtnServiceInput(
846                         serviceName,
847                         Action.Delete,
848                         service.getServiceZEnd().getServiceFormat().getName(),
849                         service.getServiceAEnd().getServiceRate(),
850                         pathDescription,
851                         false),
852                 serviceType);
853         sendNotificationsWithPathDescription(
854             ServicePathNotificationTypes.ServiceDelete,
855             serviceName,
856             RpcStatusEx.Successful,
857             OPERATION_SUCCESSFUL,
858             pathDescription,
859             createLinkForNotif(
860                 renderingResults.stream()
861                     .flatMap(rr -> rr.getOtnLinkTps().stream())
862                     .collect(Collectors.toList())),
863             getSupportedLinks(
864                 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
865                 serviceType),
866             serviceType);
867         return true;
868     }
869
870     /**
871      * Send renderer notification.
872      * @param servicePathNotificationTypes ServicePathNotificationTypes
873      * @param serviceName String
874      * @param rpcStatusEx RpcStatusEx
875      * @param message String
876      */
877     private void sendNotifications(
878             ServicePathNotificationTypes servicePathNotificationTypes,
879             String serviceName,
880             RpcStatusEx rpcStatusEx,
881             String message) {
882
883         notification.send(
884             servicePathNotificationTypes,
885             serviceName,
886             rpcStatusEx,
887             message
888         );
889     }
890
891     /**
892      * Send renderer notification with path description information.
893      * @param servicePathNotificationTypes ServicePathNotificationTypes
894      * @param serviceName String
895      * @param rpcStatusEx RpcStatusEx
896      * @param message String
897      * @param pathDescription PathDescription
898      */
899     private void sendNotificationsWithPathDescription(
900             ServicePathNotificationTypes servicePathNotificationTypes,
901             String serviceName,
902             RpcStatusEx rpcStatusEx,
903             String message,
904             PathDescription pathDescription,
905             Link notifLink,
906             Set<String> supportedLinks,
907             String serviceType) {
908
909         notification.send(
910             notification.buildNotification(
911                 servicePathNotificationTypes,
912                 serviceName,
913                 rpcStatusEx,
914                 message,
915                 pathDescription,
916                 notifLink,
917                 supportedLinks,
918                 serviceType
919             )
920         );
921     }
922
923     private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
924         return
925             otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
926                 ? null
927                 : new LinkBuilder()
928                     .setATermination(
929                         new ATerminationBuilder()
930                             .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
931                             .setTpId(otnLinkTerminationPoints.get(0).getTpId())
932                             .build())
933                     .setZTermination(
934                         new ZTerminationBuilder()
935                             .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
936                             .setTpId(otnLinkTerminationPoints.get(1).getTpId())
937                             .build())
938                     .build();
939     }
940
941     private Set<String> getSupportedLinks(Set<String> allSupportLinks, String serviceType) {
942         //TODO a Map might be more indicated here
943         switch (serviceType) {
944             case StringConstants.SERVICE_TYPE_10GE:
945             case StringConstants.SERVICE_TYPE_1GE:
946                 return allSupportLinks.stream()
947                     .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toSet());
948             case StringConstants.SERVICE_TYPE_100GE_M:
949                 return allSupportLinks.stream()
950                     .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toSet());
951             case StringConstants.SERVICE_TYPE_ODU4:
952             case StringConstants.SERVICE_TYPE_100GE_S:
953                 return allSupportLinks.stream()
954                     .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toSet());
955             case StringConstants.SERVICE_TYPE_ODUC4:
956                 return allSupportLinks.stream()
957                     .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toSet());
958             default:
959                 return null;
960         }
961     }
962 }