2 * Copyright © 2017 AT&T and others. All rights reserved.
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
8 package org.opendaylight.transportpce.renderer.provisiondevice;
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;
17 import java.util.Optional;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24 import java.util.stream.Collectors;
25 import org.opendaylight.mdsal.binding.api.DataBroker;
26 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
27 import org.opendaylight.mdsal.binding.api.ReadTransaction;
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.servicepath.ServicePathDirection;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
42 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownInputBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210927.mapping.Mapping;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSp;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSpBuilder;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
61 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
62 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
63 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
66 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
67 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.PathDescription;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.ServicePathNotificationTypes;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTp;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.olm.get.pm.input.ResourceIdentifierBuilder;
76 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.optical.renderer.nodes.Nodes;
77 import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev210511.OtnLinkType;
78 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
79 import org.opendaylight.yangtools.yang.binding.Notification;
80 import org.opendaylight.yangtools.yang.common.RpcResult;
81 import org.opendaylight.yangtools.yang.common.Uint32;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public class RendererServiceOperationsImpl implements RendererServiceOperations {
88 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
89 "Device rendering was not successful! Rendering will be rolled back.";
90 private static final String OLM_ROLL_BACK_MSG =
91 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
92 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
93 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
94 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
95 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
96 private static final String FAILED = "Failed";
97 private static final String OPERATION_FAILED = "Operation Failed";
98 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
99 private static final int NUMBER_OF_THREADS = 4;
101 private final DeviceRendererService deviceRenderer;
102 private final OtnDeviceRendererService otnDeviceRenderer;
103 private final TransportpceOlmService olmService;
104 private final DataBroker dataBroker;
105 private final NotificationPublishService notificationPublishService;
106 private final PortMapping portMapping;
107 private ListeningExecutorService executor;
109 public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
110 OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
111 DataBroker dataBroker, NotificationPublishService notificationPublishService, PortMapping portMapping) {
112 this.deviceRenderer = deviceRenderer;
113 this.otnDeviceRenderer = otnDeviceRenderer;
114 this.olmService = olmService;
115 this.dataBroker = dataBroker;
116 this.notificationPublishService = notificationPublishService;
117 this.portMapping = portMapping;
118 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
122 public ListenableFuture<ServiceImplementationRequestOutput>
123 serviceImplementation(ServiceImplementationRequestInput input) {
124 LOG.info("Calling service impl request {}", input.getServiceName());
125 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
128 public ServiceImplementationRequestOutput call() throws Exception {
129 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
130 RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
131 Uint32 serviceRate = getServiceRate(input);
132 String serviceType = ServiceTypes.getServiceType(
133 input.getServiceAEnd().getServiceFormat().getName(),
135 (NodeTypes.Xpdr.equals(portMapping.getNode(input.getServiceAEnd().getNodeId())
136 .getNodeInfo().getNodeType())
137 && input.getServiceAEnd().getTxDirection() != null
138 && input.getServiceAEnd().getTxDirection().getPort() != null
139 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null)
140 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
141 input.getServiceAEnd().getTxDirection().getPort().getPortName())
144 switch (serviceType) {
145 case StringConstants.SERVICE_TYPE_100GE_T:
146 case StringConstants.SERVICE_TYPE_400GE:
147 case StringConstants.SERVICE_TYPE_OTU4:
148 case StringConstants.SERVICE_TYPE_OTUC4:
149 if (!manageServicePathCreation(input, serviceType)) {
150 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
154 case StringConstants.SERVICE_TYPE_1GE:
155 case StringConstants.SERVICE_TYPE_10GE:
156 case StringConstants.SERVICE_TYPE_100GE_M:
157 case StringConstants.SERVICE_TYPE_100GE_S:
158 case StringConstants.SERVICE_TYPE_ODU4:
159 case StringConstants.SERVICE_TYPE_ODUC4:
160 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
161 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
166 LOG.error("unsupported service-type");
167 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
170 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
171 OPERATION_SUCCESSFUL);
177 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
178 String serviceName = input.getServiceName();
179 LOG.info("Calling service delete request {}", serviceName);
180 return executor.submit(new Callable<ServiceDeleteOutput>() {
183 public ServiceDeleteOutput call() throws Exception {
184 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
185 RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
186 // Obtain path description
188 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
189 .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
190 if (pathDescriptionOpt.isEmpty()) {
191 LOG.error("Unable to get path description for service {}!", serviceName);
192 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
193 RpcStatusEx.Failed, "Unable to get path description for service");
194 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
197 PathDescription pathDescription = pathDescriptionOpt.get();
198 Mapping mapping = portMapping.getMapping(service.getServiceAEnd().getNodeId().getValue(),
199 service.getServiceAEnd().getTxDirection().getPort().getPortName());
200 String serviceType = ServiceTypes.getServiceType(service.getServiceAEnd().getServiceFormat().getName(),
201 service.getServiceAEnd().getServiceRate(), mapping);
202 switch (serviceType) {
203 case StringConstants.SERVICE_TYPE_100GE_T:
204 case StringConstants.SERVICE_TYPE_400GE:
205 case StringConstants.SERVICE_TYPE_OTU4:
206 case StringConstants.SERVICE_TYPE_OTUC4:
207 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
208 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
212 case StringConstants.SERVICE_TYPE_1GE:
213 case StringConstants.SERVICE_TYPE_10GE:
214 case StringConstants.SERVICE_TYPE_100GE_M:
215 case StringConstants.SERVICE_TYPE_100GE_S:
216 case StringConstants.SERVICE_TYPE_ODU4:
217 case StringConstants.SERVICE_TYPE_ODUC4:
218 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
219 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
224 LOG.error("unsupported service-type");
225 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
228 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
233 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
234 value = "UPM_UNCALLED_PRIVATE_METHOD",
235 justification = "call in call() method")
236 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
237 if (input.getServiceAEnd() == null) {
238 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
241 if (input.getServiceAEnd().getServiceRate() != null) {
242 return input.getServiceAEnd().getServiceRate();
244 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
245 ServiceFormat.OTU, Map.of(
246 "OTUCn", Uint32.valueOf(400),
247 "OTU4", Uint32.valueOf(100),
248 "OTU2", Uint32.valueOf(10),
249 "OTU2e", Uint32.valueOf(10)),
250 ServiceFormat.ODU, Map.of(
251 "ODUCn",Uint32.valueOf(400),
252 "ODU4", Uint32.valueOf(100),
253 "ODU2", Uint32.valueOf(10),
254 "ODU2e", Uint32.valueOf(10),
255 "ODU0", Uint32.valueOf(1)));
256 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
257 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
258 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
262 ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
263 ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
264 : input.getServiceAEnd().getOduServiceRate().getSimpleName();
265 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
266 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
267 input.getServiceName(), serviceName);
270 return formatRateMap.get(input.getServiceAEnd().getServiceFormat()).get(serviceName);
273 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
274 value = "UPM_UNCALLED_PRIVATE_METHOD",
275 justification = "call in call() method")
276 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
277 throws InterruptedException, ExecutionException, TimeoutException {
278 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
279 Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
280 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
281 return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
284 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
285 value = "UPM_UNCALLED_PRIVATE_METHOD",
286 justification = "call in call() method")
287 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
288 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
289 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
290 .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
291 .child(ServicePaths.class, new ServicePathsKey(serviceName))
292 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
293 .service.path.PathDescription.class);
294 ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
296 LOG.debug("Getting path description for service {}", serviceName);
297 return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
298 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
299 } catch (InterruptedException | ExecutionException | TimeoutException e) {
300 LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
302 return Optional.empty();
306 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
307 value = "UPM_UNCALLED_PRIVATE_METHOD",
308 justification = "call in call() method")
309 private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
310 ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
311 LOG.info(RENDERING_DEVICES_A_Z_MSG);
312 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
313 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
314 RENDERING_DEVICES_A_Z_MSG);
315 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
316 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
317 ServicePathDirection.A_TO_Z));
319 LOG.info("Rendering devices Z-A");
320 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
321 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
322 RENDERING_DEVICES_Z_A_MSG);
323 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
324 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
325 ServicePathDirection.Z_TO_A));
326 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
327 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
329 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
331 LOG.info("Waiting for A-Z and Z-A device renderers ...");
332 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
333 } catch (InterruptedException | ExecutionException | TimeoutException e) {
334 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
335 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
336 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
337 DEVICE_RENDERING_ROLL_BACK_MSG);
338 //FIXME we can't do rollback here, because we don't have rendering results.
339 return renderingResults;
342 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
343 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
344 this.deviceRenderer));
345 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
346 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
347 this.deviceRenderer));
348 return renderingResults;
351 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
352 value = "UPM_UNCALLED_PRIVATE_METHOD",
353 justification = "call in call() method")
354 private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
355 OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA, String serviceType) {
356 LOG.info(RENDERING_DEVICES_A_Z_MSG);
357 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
358 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
359 RENDERING_DEVICES_A_Z_MSG);
360 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
361 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
362 LOG.info(RENDERING_DEVICES_Z_A_MSG);
363 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
364 otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
365 RENDERING_DEVICES_Z_A_MSG);
366 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
367 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
368 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
369 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
370 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
372 LOG.info("Waiting for A-Z and Z-A device renderers ...");
373 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
374 } catch (InterruptedException | ExecutionException | TimeoutException e) {
375 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
376 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
377 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
378 DEVICE_RENDERING_ROLL_BACK_MSG);
379 //FIXME we can't do rollback here, because we don't have rendering results.
380 return otnRenderingResults;
382 for (int i = 0; i < otnRenderingResults.size(); i++) {
383 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("DeviceTask n° " + i + 1,
384 ! otnRenderingResults.get(i).isSuccess(), otnRenderingResults.get(i).getRenderedNodeInterfaces(),
385 this.deviceRenderer));
387 return otnRenderingResults;
390 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
391 value = "UPM_UNCALLED_PRIVATE_METHOD",
392 justification = "call in call() method")
393 private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
394 ServicePowerSetupInput powerSetupInputZtoA) {
395 LOG.info("Olm power setup A-Z");
396 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
397 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
398 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
399 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
401 LOG.info("OLM power setup Z-A");
402 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
403 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
404 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
405 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
406 ListenableFuture<List<OLMRenderingResult>> olmFutures =
407 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
409 List<OLMRenderingResult> olmResults;
411 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
412 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
413 } catch (InterruptedException | ExecutionException | TimeoutException e) {
414 LOG.warn(OLM_ROLL_BACK_MSG, e);
415 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
416 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
418 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
419 this.olmService, powerSetupInputAtoZ));
420 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
421 this.olmService, powerSetupInputZtoA));
425 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
426 this.olmService, powerSetupInputAtoZ));
427 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
428 this.olmService, powerSetupInputZtoA));
431 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
432 value = "UPM_UNCALLED_PRIVATE_METHOD",
433 justification = "call in call() method")
434 private boolean isServiceActivated(String nodeId, String tpId) {
435 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
436 for (int i = 0; i < 3; i++) {
437 List<Measurements> measurements = getMeasurements(nodeId, tpId);
438 if (measurements == null) {
439 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
442 if (verifyPreFecBer(measurements)) {
446 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
447 } catch (InterruptedException ex) {
448 Thread.currentThread().interrupt();
451 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
455 private List<Measurements> getMeasurements(String nodeId, String tp) {
456 GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder()
458 .setGranularity(PmGranularity._15min)
459 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
460 .setResourceType(ResourceTypeEnum.Interface);
463 Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
464 RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
465 GetPmOutput getPmOutput = getPmRpcResult.getResult();
466 if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
467 LOG.info("successfully finished calling OLM's get PM");
468 return getPmOutput.getMeasurements();
471 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
474 } catch (ExecutionException | InterruptedException e) {
475 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
480 private boolean verifyPreFecBer(List<Measurements> measurements) {
481 double preFecCorrectedErrors = Double.MIN_VALUE;
482 double fecUncorrectableBlocks = Double.MIN_VALUE;
484 for (Measurements measurement : measurements) {
485 switch (measurement.getPmparameterName()) {
486 case "preFECCorrectedErrors":
487 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
489 case "FECUncorrectableBlocks":
490 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
497 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
498 fecUncorrectableBlocks);
500 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
501 LOG.error("Data has uncorrectable errors, BER test failed");
505 double numOfBitsPerSecond = 112000000000d;
506 double threshold = 0.00002d;
507 double result = preFecCorrectedErrors / numOfBitsPerSecond;
508 LOG.info("PreFEC value is {}", Double.toString(result));
509 return result <= threshold;
512 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
513 value = "UPM_UNCALLED_PRIVATE_METHOD",
514 justification = "call in call() method")
515 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
516 ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
517 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
518 ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
519 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
520 // Rollback should be same for all conditions, so creating a new one
521 RollbackProcessor rollbackProcessor = new RollbackProcessor();
522 List<DeviceRenderingResult> renderingResults =
523 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
524 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
525 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
526 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
529 ServicePowerSetupInput olmPowerSetupInputAtoZ =
530 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
531 ServicePowerSetupInput olmPowerSetupInputZtoA =
532 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
533 olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
534 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
535 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
536 input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
539 // run service activation test twice - once on source node and once on
541 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
542 if ((nodes == null) || (nodes.isEmpty())) {
546 Nodes sourceNode = nodes.get(0);
547 Nodes destNode = nodes.get(nodes.size() - 1);
548 String srcNetworkTp =
549 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
550 ? sourceNode.getDestTp()
551 : sourceNode.getSrcTp();
552 String dstNetowrkTp =
553 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
554 ? destNode.getDestTp()
555 : destNode.getSrcTp();
557 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
558 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
559 rollbackProcessor.rollbackAll();
560 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
561 input.getServiceName(), RpcStatusEx.Failed,
562 "Service activation test failed.");
565 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
566 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
567 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
569 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
570 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
571 notifLink, null, serviceType);
575 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
576 value = "UPM_UNCALLED_PRIVATE_METHOD",
577 justification = "call in call() method")
578 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
579 throws InterruptedException {
580 ServicePathInputData servicePathInputDataAtoZ =
581 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
582 ServicePathInputData servicePathInputDataZtoA =
583 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
584 // OLM turn down power
586 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
587 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
588 RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
589 ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
590 // TODO add some flag rather than string
591 if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
592 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
593 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
594 "Service power turndown failed on A-to-Z path for service");
597 LOG.debug("Turning down power on Z-to-A path");
598 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
599 "Turning down power on Z-to-A path");
600 ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
601 // TODO add some flag rather than string
602 if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
603 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
604 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
605 "Service power turndown failed on Z-to-A path for service");
608 } catch (InterruptedException | ExecutionException | TimeoutException e) {
609 LOG.error("Error while turning down power!", e);
612 // delete service path with renderer
613 LOG.info("Deleting service path via renderer");
614 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
615 "Deleting service path via renderer");
616 RollbackProcessor rollbackProcessor = new RollbackProcessor();
617 List<DeviceRenderingResult> renderingResults =
618 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
619 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
620 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
621 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
623 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
624 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, null, serviceType);
628 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
629 value = "UPM_UNCALLED_PRIVATE_METHOD",
630 justification = "call in call() method")
631 private boolean manageOtnServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
632 Uint32 serviceRate) {
634 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
635 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
636 input.getServiceAEnd().getServiceFormat().getName(),
638 input.getPathDescription(), true);
640 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
641 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
642 input.getServiceZEnd().getServiceFormat().getName(),
644 input.getPathDescription(), false);
645 // Rollback should be same for all conditions, so creating a new one
646 RollbackProcessor rollbackProcessor = new RollbackProcessor();
647 List<OtnDeviceRenderingResult> renderingResults =
648 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
649 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
650 rollbackProcessor.rollbackAll();
651 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
652 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
655 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
656 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
657 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
658 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription());
659 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
661 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
662 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
663 notifLink, supportedLinks, serviceType);
667 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
668 value = "UPM_UNCALLED_PRIVATE_METHOD",
669 justification = "call in call() method")
670 private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
671 Services service, String serviceType) {
673 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
674 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
675 service.getServiceAEnd().getServiceFormat().getName(),
676 service.getServiceAEnd().getServiceRate(),
677 pathDescription, true);
679 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
680 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
681 service.getServiceZEnd().getServiceFormat().getName(),
682 service.getServiceAEnd().getServiceRate(),
683 pathDescription, false);
684 LOG.info("Deleting otn-service path {} via renderer", serviceName);
685 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
686 "Deleting otn-service path via renderer");
688 RollbackProcessor rollbackProcessor = new RollbackProcessor();
689 List<OtnDeviceRenderingResult> renderingResults =
690 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
692 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
693 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
694 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
695 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(pathDescription);
696 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
698 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
699 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, supportedLinks,
705 * Send renderer notification.
706 * @param servicePathNotificationTypes ServicePathNotificationTypes
707 * @param serviceName String
708 * @param rpcStatusEx RpcStatusEx
709 * @param message String
711 private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
712 RpcStatusEx rpcStatusEx, String message) {
713 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
714 null, null, null, null);
719 * Send renderer notification with path description information.
720 * @param servicePathNotificationTypes ServicePathNotificationTypes
721 * @param serviceName String
722 * @param rpcStatusEx RpcStatusEx
723 * @param message String
724 * @param pathDescription PathDescription
726 private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
727 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
728 Link notifLink, List<String> supportedLinks, String serviceType) {
729 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
730 pathDescription, notifLink, supportedLinks, serviceType);
735 * Build notification containing path description information.
736 * @param servicePathNotificationTypes ServicePathNotificationTypes
737 * @param serviceName String
738 * @param rpcStatusEx RpcStatusEx
739 * @param message String
740 * @param pathDescription PathDescription
741 * @return notification with RendererRpcResultSp type.
743 private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
744 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
745 Link notifLink, List<String> supportedLinks, String serviceType) {
746 RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
747 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
748 .setStatusMessage(message)
749 .setServiceType(serviceType);
750 if (pathDescription != null) {
751 builder.setAToZDirection(pathDescription.getAToZDirection())
752 .setZToADirection(pathDescription.getZToADirection());
754 if (notifLink != null) {
755 builder.setLink(notifLink);
757 if (supportedLinks != null) {
758 builder.setLinkId(supportedLinks);
760 return builder.build();
764 * Send renderer notification.
765 * @param notification Notification
767 private void send(Notification notification) {
769 LOG.info("Sending notification {}", notification);
770 notificationPublishService.putNotification(notification);
771 } catch (InterruptedException e) {
772 LOG.info("notification offer rejected: ", e);
773 Thread.currentThread().interrupt();
777 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
778 if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
781 return new LinkBuilder()
782 .setATermination(new ATerminationBuilder()
783 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
784 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
786 .setZTermination(new ZTerminationBuilder()
787 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
788 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
793 private List<String> getSupportedLinks(List<String> allSupportLinks, String serviceType) {
794 switch (serviceType) {
795 case StringConstants.SERVICE_TYPE_10GE:
796 case StringConstants.SERVICE_TYPE_1GE:
797 return allSupportLinks.stream()
798 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toList());
799 case StringConstants.SERVICE_TYPE_100GE_M:
800 return allSupportLinks.stream()
801 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toList());
802 case StringConstants.SERVICE_TYPE_ODU4:
803 case StringConstants.SERVICE_TYPE_100GE_S:
804 return allSupportLinks.stream()
805 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
806 case StringConstants.SERVICE_TYPE_ODUC4:
807 return allSupportLinks.stream()
808 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());