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