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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.util.ArrayList;
16 import java.util.List;
18 import java.util.Optional;
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.NotificationPublishService;
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.networkutils.rev220630.OtnLinkType;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownInputBuilder;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
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.resource.types.rev161014.ResourceTypeEnum;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
66 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.Services;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.PathDescription;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.PmGranularity;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.link.tp.LinkTp;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.olm.get.pm.input.ResourceIdentifierBuilder;
76 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.optical.renderer.nodes.Nodes;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.binding.Notification;
79 import org.opendaylight.yangtools.yang.common.Uint32;
80 import org.osgi.service.component.annotations.Activate;
81 import org.osgi.service.component.annotations.Component;
82 import org.osgi.service.component.annotations.Reference;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
87 @Component(immediate = true)
88 public class RendererServiceOperationsImpl implements RendererServiceOperations {
90 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
91 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
92 "Device rendering was not successful! Rendering will be rolled back.";
93 private static final String OLM_ROLL_BACK_MSG =
94 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
95 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
96 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
97 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
98 private static final String FAILED = "Failed";
99 private static final String OPERATION_FAILED = "Operation Failed";
100 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
101 private static final int NUMBER_OF_THREADS = 4;
103 private final DeviceRendererService deviceRenderer;
104 private final OtnDeviceRendererService otnDeviceRenderer;
105 private final TransportpceOlmService olmService;
106 private final DataBroker dataBroker;
107 private final NotificationPublishService notificationPublishService;
108 private final PortMapping portMapping;
109 private ListeningExecutorService executor;
112 public RendererServiceOperationsImpl(@Reference DeviceRendererService deviceRenderer,
113 @Reference OtnDeviceRendererService otnDeviceRenderer,
114 @Reference TransportpceOlmService olmService,
115 @Reference DataBroker dataBroker,
116 @Reference NotificationPublishService notificationPublishService,
117 @Reference PortMapping portMapping) {
118 this.deviceRenderer = deviceRenderer;
119 this.otnDeviceRenderer = otnDeviceRenderer;
120 this.olmService = olmService;
121 this.dataBroker = dataBroker;
122 this.notificationPublishService = notificationPublishService;
123 this.portMapping = portMapping;
124 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
125 LOG.debug("RendererServiceOperationsImpl instantiated");
129 public ListenableFuture<ServiceImplementationRequestOutput>
130 serviceImplementation(ServiceImplementationRequestInput input, boolean isTempService) {
131 LOG.info("Calling service impl request {}", input.getServiceName());
132 LOG.debug("Check if it is temp-service {}", isTempService);
133 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
136 public ServiceImplementationRequestOutput call() throws Exception {
138 ServicePathNotificationTypes.ServiceImplementationRequest,
139 input.getServiceName(),
141 "Service compliant, submitting service implementation Request ...");
142 Uint32 serviceRate = getServiceRate(input);
143 LOG.info("Using {}G rate", serviceRate);
144 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220922
145 .network.Nodes mappingNode =
146 portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
147 ? portMapping.getNode(input.getServiceAEnd().getNodeId())
149 String serviceType = ServiceTypes.getServiceType(
150 input.getServiceAEnd().getServiceFormat().getName(),
153 && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
154 && input.getServiceAEnd().getTxDirection() != null
155 && input.getServiceAEnd().getTxDirection().getPort() != null
156 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
157 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
158 input.getServiceAEnd().getTxDirection().getPort().getPortName())
160 //TODO a Map might be more indicated here
161 switch (serviceType) {
162 case StringConstants.SERVICE_TYPE_100GE_T:
163 case StringConstants.SERVICE_TYPE_400GE:
164 case StringConstants.SERVICE_TYPE_OTU4:
165 case StringConstants.SERVICE_TYPE_OTUC2:
166 case StringConstants.SERVICE_TYPE_OTUC3:
167 case StringConstants.SERVICE_TYPE_OTUC4:
168 LOG.debug("Check temp service {}", isTempService);
169 if (!manageServicePathCreation(input, serviceType, isTempService)) {
170 return ModelMappingUtils
171 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
174 case StringConstants.SERVICE_TYPE_1GE:
175 case StringConstants.SERVICE_TYPE_10GE:
176 case StringConstants.SERVICE_TYPE_100GE_M:
177 case StringConstants.SERVICE_TYPE_100GE_S:
178 case StringConstants.SERVICE_TYPE_ODU4:
179 case StringConstants.SERVICE_TYPE_ODUC2:
180 case StringConstants.SERVICE_TYPE_ODUC3:
181 case StringConstants.SERVICE_TYPE_ODUC4:
182 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
183 return ModelMappingUtils
184 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
188 LOG.error("unsupported service-type");
189 return ModelMappingUtils
190 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
192 return ModelMappingUtils
193 .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
199 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
200 String serviceName = input.getServiceName();
201 LOG.info("Calling service delete request {}", serviceName);
202 return executor.submit(new Callable<ServiceDeleteOutput>() {
205 public ServiceDeleteOutput call() throws Exception {
207 ServicePathNotificationTypes.ServiceDelete,
210 "Service compliant, submitting service delete Request ...");
211 // Obtain path description
213 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
214 .service.path.PathDescription> pathDescriptionOpt =
215 getPathDescriptionFromDatastore(serviceName);
216 if (pathDescriptionOpt.isEmpty()) {
217 LOG.error("Unable to get path description for service {}!", serviceName);
219 ServicePathNotificationTypes.ServiceDelete,
222 "Unable to get path description for service");
223 return ModelMappingUtils
224 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
226 PathDescription pathDescription = pathDescriptionOpt.orElseThrow();
228 ServiceTypes.getServiceType(
229 service.getServiceAEnd().getServiceFormat().getName(),
230 service.getServiceAEnd().getServiceRate(),
231 service.getServiceAEnd().getTxDirection() == null
232 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
234 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
235 .getPort().getPortName() == null
237 : portMapping.getMapping(
238 service.getServiceAEnd().getNodeId().getValue(),
239 service.getServiceAEnd().getTxDirection().values().stream().findFirst()
240 .orElseThrow().getPort().getPortName()));
241 switch (serviceType) {
242 case StringConstants.SERVICE_TYPE_100GE_T:
243 case StringConstants.SERVICE_TYPE_400GE:
244 case StringConstants.SERVICE_TYPE_OTU4:
245 case StringConstants.SERVICE_TYPE_OTUC2:
246 case StringConstants.SERVICE_TYPE_OTUC3:
247 case StringConstants.SERVICE_TYPE_OTUC4:
248 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
249 return ModelMappingUtils
250 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
253 case StringConstants.SERVICE_TYPE_1GE:
254 case StringConstants.SERVICE_TYPE_10GE:
255 case StringConstants.SERVICE_TYPE_100GE_M:
256 case StringConstants.SERVICE_TYPE_100GE_S:
257 case StringConstants.SERVICE_TYPE_ODU4:
258 case StringConstants.SERVICE_TYPE_ODUC2:
259 case StringConstants.SERVICE_TYPE_ODUC3:
260 case StringConstants.SERVICE_TYPE_ODUC4:
261 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
262 return ModelMappingUtils
263 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
267 LOG.error("unsupported service-type");
268 return ModelMappingUtils
269 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
271 return ModelMappingUtils
272 .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
278 value = "UPM_UNCALLED_PRIVATE_METHOD",
279 justification = "call in call() method")
280 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
281 if (input.getServiceAEnd() == null) {
282 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
285 if (input.getServiceAEnd().getServiceRate() != null) {
286 return input.getServiceAEnd().getServiceRate();
288 LOG.warn("Input should have rate if you are using 200 or 300G");
289 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
290 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
291 ServiceFormat.OTU, Map.of(
292 "OTUCn", Uint32.valueOf(400),
293 "OTU4", Uint32.valueOf(100),
294 "OTU2", Uint32.valueOf(10),
295 "OTU2e", Uint32.valueOf(10)),
296 ServiceFormat.ODU, Map.of(
297 "ODUCn",Uint32.valueOf(400),
298 "ODU4", Uint32.valueOf(100),
299 "ODU2", Uint32.valueOf(10),
300 "ODU2e", Uint32.valueOf(10),
301 "ODU0", Uint32.valueOf(1)));
302 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
303 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
304 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
308 ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
309 ? input.getServiceAEnd().getOtuServiceRate().toString().split("\\{")[0]
310 : input.getServiceAEnd().getOduServiceRate().toString().split("\\{")[0];
311 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
312 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
313 input.getServiceName(), serviceName);
317 .get(input.getServiceAEnd().getServiceFormat())
322 value = "UPM_UNCALLED_PRIVATE_METHOD",
323 justification = "call in call() method")
324 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
325 throws InterruptedException, ExecutionException, TimeoutException {
326 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
327 return this.olmService
328 .servicePowerTurndown(
329 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build())
330 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS)
335 value = "UPM_UNCALLED_PRIVATE_METHOD",
336 justification = "call in call() method")
337 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
338 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
339 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
340 .service.path.PathDescription> pathDescriptionIID =
341 InstanceIdentifier.create(ServicePathList.class)
342 .child(ServicePaths.class, new ServicePathsKey(serviceName))
343 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
344 .service.path.PathDescription.class);
346 LOG.debug("Getting path description for service {}", serviceName);
347 return this.dataBroker.newReadOnlyTransaction()
348 .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
349 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
350 } catch (InterruptedException | ExecutionException | TimeoutException e) {
351 LOG.warn("Exception while getting path description from datastore {} for service {}!",
352 pathDescriptionIID, serviceName, e);
353 return Optional.empty();
358 value = "UPM_UNCALLED_PRIVATE_METHOD",
359 justification = "call in call() method")
360 private List<DeviceRenderingResult> deviceRendering(
361 RollbackProcessor rollbackProcessor,
362 ServicePathInputData servicePathDataAtoZ,
363 ServicePathInputData servicePathDataZtoA) {
365 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
366 // Do notifications & LOG.info deserve this ?
367 LOG.info(RENDERING_DEVICES_A_Z_MSG);
369 ServicePathNotificationTypes.ServiceImplementationRequest,
370 servicePathDataAtoZ.getServicePathInput().getServiceName(),
372 RENDERING_DEVICES_A_Z_MSG);
373 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
374 this.executor.submit(
375 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z));
377 LOG.info(RENDERING_DEVICES_Z_A_MSG);
379 ServicePathNotificationTypes.ServiceImplementationRequest,
380 servicePathDataZtoA.getServicePathInput().getServiceName(),
382 RENDERING_DEVICES_Z_A_MSG);
383 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
384 this.executor.submit(
385 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A));
387 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
388 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
390 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
392 LOG.info("Waiting for A-Z and Z-A device renderers ...");
393 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
394 } catch (InterruptedException | ExecutionException | TimeoutException e) {
395 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
397 ServicePathNotificationTypes.ServiceImplementationRequest,
398 servicePathDataAtoZ.getServicePathInput().getServiceName(),
400 DEVICE_RENDERING_ROLL_BACK_MSG);
401 //FIXME we can't do rollback here, because we don't have rendering results.
402 return renderingResults;
405 rollbackProcessor.addTask(
406 new DeviceRenderingRollbackTask(
408 ! renderingResults.get(0).isSuccess(),
409 renderingResults.get(0).getRenderedNodeInterfaces(),
410 this.deviceRenderer));
411 rollbackProcessor.addTask(
412 new DeviceRenderingRollbackTask("ZtoADeviceTask",
413 ! renderingResults.get(1).isSuccess(),
414 renderingResults.get(1).getRenderedNodeInterfaces(),
415 this.deviceRenderer));
416 return renderingResults;
420 value = "UPM_UNCALLED_PRIVATE_METHOD",
421 justification = "call in call() method")
422 private List<OtnDeviceRenderingResult> otnDeviceRendering(
423 RollbackProcessor rollbackProcessor,
424 OtnServicePathInput otnServicePathAtoZ,
425 OtnServicePathInput otnServicePathZtoA,
426 String serviceType) {
428 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
429 // Do notifications & LOG.info deserve this ?
430 LOG.info(RENDERING_DEVICES_A_Z_MSG);
432 ServicePathNotificationTypes.ServiceImplementationRequest,
433 otnServicePathAtoZ.getServiceName(),
435 RENDERING_DEVICES_A_Z_MSG);
436 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
437 this.executor.submit(
438 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
440 LOG.info(RENDERING_DEVICES_Z_A_MSG);
442 ServicePathNotificationTypes.ServiceImplementationRequest,
443 otnServicePathZtoA.getServiceName(),
445 RENDERING_DEVICES_Z_A_MSG);
446 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
447 this.executor.submit(
448 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
450 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
451 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
452 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
454 LOG.info("Waiting for A-Z and Z-A device renderers ...");
455 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
456 } catch (InterruptedException | ExecutionException | TimeoutException e) {
457 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
459 ServicePathNotificationTypes.ServiceImplementationRequest,
460 otnServicePathAtoZ.getServiceName(),
462 DEVICE_RENDERING_ROLL_BACK_MSG);
463 //FIXME we can't do rollback here, because we don't have rendering results.
464 return otnRenderingResults;
466 for (int i = 0; i < otnRenderingResults.size(); i++) {
467 rollbackProcessor.addTask(
468 new DeviceRenderingRollbackTask(
469 "DeviceTask n° " + i + 1,
470 ! otnRenderingResults.get(i).isSuccess(),
471 otnRenderingResults.get(i).getRenderedNodeInterfaces(),
472 this.deviceRenderer));
474 return otnRenderingResults;
478 value = "UPM_UNCALLED_PRIVATE_METHOD",
479 justification = "call in call() method")
480 private void olmPowerSetup(
481 RollbackProcessor rollbackProcessor,
482 ServicePowerSetupInput powerSetupInputAtoZ,
483 ServicePowerSetupInput powerSetupInputZtoA, boolean isTempService) {
485 //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
486 // Do notifications & LOG.info deserve this ?
487 //TODO use constants for LOG.info & notifications common messages
488 // if the service create is a temp-service, OLM will be skipped
490 LOG.info("For temp-service create OLM is not computed and skipped");
493 LOG.info("Olm power setup A-Z");
495 ServicePathNotificationTypes.ServiceImplementationRequest,
496 powerSetupInputAtoZ.getServiceName(),
498 "Olm power setup A-Z");
499 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
500 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
502 LOG.info("OLM power setup Z-A");
504 ServicePathNotificationTypes.ServiceImplementationRequest,
505 powerSetupInputAtoZ.getServiceName(),
507 "Olm power setup Z-A");
508 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
509 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
510 ListenableFuture<List<OLMRenderingResult>> olmFutures =
511 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
513 List<OLMRenderingResult> olmResults;
515 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
516 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
517 } catch (InterruptedException | ExecutionException | TimeoutException e) {
518 LOG.warn(OLM_ROLL_BACK_MSG, e);
520 ServicePathNotificationTypes.ServiceImplementationRequest,
521 powerSetupInputAtoZ.getServiceName(),
524 rollbackProcessor.addTask(
525 new OlmPowerSetupRollbackTask("AtoZOLMTask", true, this.olmService, powerSetupInputAtoZ));
526 rollbackProcessor.addTask(
527 new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, this.olmService, powerSetupInputZtoA));
530 rollbackProcessor.addTask(
531 new OlmPowerSetupRollbackTask(
533 !olmResults.get(0).isSuccess(),
535 powerSetupInputAtoZ));
536 rollbackProcessor.addTask(
537 new OlmPowerSetupRollbackTask(
539 !olmResults.get(1).isSuccess(),
541 powerSetupInputZtoA));
545 value = "UPM_UNCALLED_PRIVATE_METHOD",
546 justification = "call in call() method")
547 private boolean isServiceActivated(String nodeId, String tpId) {
548 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
549 for (int i = 0; i < 3; i++) {
550 List<Measurements> measurements = getMeasurements(nodeId, tpId);
551 if (measurements == null) {
552 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
555 if (verifyPreFecBer(measurements)) {
559 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
560 } catch (InterruptedException ex) {
561 Thread.currentThread().interrupt();
564 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
568 private List<Measurements> getMeasurements(String nodeId, String tp) {
570 GetPmOutput getPmOutput =
573 new GetPmInputBuilder()
575 .setGranularity(PmGranularity._15min)
576 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
577 .setResourceType(ResourceTypeEnum.Interface)
581 if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
582 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
584 LOG.info("successfully finished calling OLM's get PM");
585 return getPmOutput.getMeasurements();
589 } catch (ExecutionException | InterruptedException e) {
590 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
595 private boolean verifyPreFecBer(List<Measurements> measurements) {
596 double preFecCorrectedErrors = Double.MIN_VALUE;
597 double fecUncorrectableBlocks = Double.MIN_VALUE;
599 for (Measurements measurement : measurements) {
600 switch (measurement.getPmparameterName()) {
601 case "preFECCorrectedErrors":
602 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
604 case "FECUncorrectableBlocks":
605 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
612 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
613 preFecCorrectedErrors, fecUncorrectableBlocks);
615 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
616 LOG.error("Data has uncorrectable errors, BER test failed");
620 double numOfBitsPerSecond = 112000000000d;
621 double threshold = 0.00002d;
622 double result = preFecCorrectedErrors / numOfBitsPerSecond;
623 LOG.info("PreFEC value is {}", Double.toString(result));
624 return result <= threshold;
628 value = "UPM_UNCALLED_PRIVATE_METHOD",
629 justification = "call in call() method")
630 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
631 boolean isTempService) {
632 ServicePathInputData servicePathInputDataAtoZ =
634 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
635 ServicePathInputData servicePathInputDataZtoA =
637 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
638 // Rollback should be same for all conditions, so creating a new one
639 RollbackProcessor rollbackProcessor = new RollbackProcessor();
640 List<DeviceRenderingResult> renderingResults =
641 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
642 if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
644 ServicePathNotificationTypes.ServiceImplementationRequest,
645 input.getServiceName(),
647 DEVICE_RENDERING_ROLL_BACK_MSG);
652 //olmPowerSetupInputAtoZ,
653 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
654 //olmPowerSetupInputZtoA
655 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input), isTempService);
656 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
658 ServicePathNotificationTypes.ServiceImplementationRequest,
659 input.getServiceName(),
664 // run service activation test twice - once on source node and once on
666 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
667 if ((nodes == null) || (nodes.isEmpty())) {
671 Nodes sourceNode = nodes.get(0);
672 Nodes destNode = nodes.get(nodes.size() - 1);
673 String srcNetworkTp =
674 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
675 ? sourceNode.getDestTp()
676 : sourceNode.getSrcTp();
677 String dstNetowrkTp =
678 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
679 ? destNode.getDestTp()
680 : destNode.getSrcTp();
682 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
683 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
684 rollbackProcessor.rollbackAll();
686 ServicePathNotificationTypes.ServiceImplementationRequest,
687 input.getServiceName(),
689 "Service activation test failed.");
692 sendNotificationsWithPathDescription(
693 ServicePathNotificationTypes.ServiceImplementationRequest,
694 input.getServiceName(),
695 RpcStatusEx.Successful,
696 OPERATION_SUCCESSFUL,
697 input.getPathDescription(),
699 renderingResults.stream()
700 .flatMap(rr -> rr.getOtnLinkTps().stream())
701 .collect(Collectors.toList())),
708 value = "UPM_UNCALLED_PRIVATE_METHOD",
709 justification = "call in call() method")
710 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
711 throws InterruptedException {
712 ServicePathInputData servicePathInputDataAtoZ =
713 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
714 ServicePathInputData servicePathInputDataZtoA =
715 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
716 // OLM turn down power
718 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
720 ServicePathNotificationTypes.ServiceDelete,
723 TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
724 // TODO add some flag rather than string
726 olmPowerTurndown(servicePathInputDataAtoZ)
728 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
730 ServicePathNotificationTypes.ServiceDelete,
733 "Service power turndown failed on A-to-Z path for service");
736 LOG.debug("Turning down power on Z-to-A path");
738 ServicePathNotificationTypes.ServiceDelete,
741 "Turning down power on Z-to-A path");
742 // TODO add some flag rather than string
744 olmPowerTurndown(servicePathInputDataZtoA)
746 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
748 ServicePathNotificationTypes.ServiceDelete,
751 "Service power turndown failed on Z-to-A path for service");
754 } catch (InterruptedException | ExecutionException | TimeoutException e) {
755 LOG.error("Error while turning down power!", e);
758 // delete service path with renderer
759 LOG.info("Deleting service path via renderer");
761 ServicePathNotificationTypes.ServiceDelete,
764 "Deleting service path via renderer");
765 sendNotificationsWithPathDescription(
766 ServicePathNotificationTypes.ServiceDelete,
768 RpcStatusEx.Successful,
769 OPERATION_SUCCESSFUL,
773 new RollbackProcessor(),
774 servicePathInputDataAtoZ,
775 servicePathInputDataZtoA)
777 .flatMap(rr -> rr.getOtnLinkTps().stream())
778 .collect(Collectors.toList())),
785 value = "UPM_UNCALLED_PRIVATE_METHOD",
786 justification = "call in call() method")
787 private boolean manageOtnServicePathCreation(
788 ServiceImplementationRequestInput input,
790 Uint32 serviceRate) {
791 // Rollback should be same for all conditions, so creating a new one
792 RollbackProcessor rollbackProcessor = new RollbackProcessor();
793 List<OtnDeviceRenderingResult> renderingResults =
798 .rendererCreateOtnServiceInput(
799 input.getServiceName(),
801 input.getServiceAEnd().getServiceFormat().getName(),
803 input.getPathDescription(),
807 .rendererCreateOtnServiceInput(
808 input.getServiceName(),
810 input.getServiceZEnd().getServiceFormat().getName(),
812 input.getPathDescription(),
815 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
816 rollbackProcessor.rollbackAll();
818 ServicePathNotificationTypes.ServiceImplementationRequest,
819 input.getServiceName(),
821 DEVICE_RENDERING_ROLL_BACK_MSG);
824 sendNotificationsWithPathDescription(
825 ServicePathNotificationTypes.ServiceImplementationRequest,
826 input.getServiceName(),
827 RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
828 input.getPathDescription(),
830 renderingResults.stream()
831 .flatMap(rr -> rr.getOtnLinkTps().stream())
832 .collect(Collectors.toList())),
834 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
841 value = "UPM_UNCALLED_PRIVATE_METHOD",
842 justification = "call in call() method")
843 private boolean manageOtnServicePathDeletion(
845 PathDescription pathDescription,
847 String serviceType) {
848 LOG.info("Deleting otn-service path {} via renderer", serviceName);
850 ServicePathNotificationTypes.ServiceDelete,
853 "Deleting otn-service path via renderer");
854 List<OtnDeviceRenderingResult> renderingResults =
856 new RollbackProcessor(),
859 .rendererCreateOtnServiceInput(
862 service.getServiceAEnd().getServiceFormat().getName(),
863 service.getServiceAEnd().getServiceRate(),
868 .rendererCreateOtnServiceInput(
871 service.getServiceZEnd().getServiceFormat().getName(),
872 service.getServiceAEnd().getServiceRate(),
876 sendNotificationsWithPathDescription(
877 ServicePathNotificationTypes.ServiceDelete,
879 RpcStatusEx.Successful,
880 OPERATION_SUCCESSFUL,
883 renderingResults.stream()
884 .flatMap(rr -> rr.getOtnLinkTps().stream())
885 .collect(Collectors.toList())),
887 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
894 * Send renderer notification.
895 * @param servicePathNotificationTypes ServicePathNotificationTypes
896 * @param serviceName String
897 * @param rpcStatusEx RpcStatusEx
898 * @param message String
900 private void sendNotifications(
901 ServicePathNotificationTypes servicePathNotificationTypes,
903 RpcStatusEx rpcStatusEx,
906 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
907 null, null, null, null));
911 * Send renderer notification with path description information.
912 * @param servicePathNotificationTypes ServicePathNotificationTypes
913 * @param serviceName String
914 * @param rpcStatusEx RpcStatusEx
915 * @param message String
916 * @param pathDescription PathDescription
918 private void sendNotificationsWithPathDescription(
919 ServicePathNotificationTypes servicePathNotificationTypes,
921 RpcStatusEx rpcStatusEx,
923 PathDescription pathDescription,
925 Set<String> supportedLinks,
926 String serviceType) {
928 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
929 pathDescription, notifLink, supportedLinks, serviceType));
933 * Build notification containing path description information.
934 * @param servicePathNotificationTypes ServicePathNotificationTypes
935 * @param serviceName String
936 * @param rpcStatusEx RpcStatusEx
937 * @param message String
938 * @param pathDescription PathDescription
939 * @return notification with RendererRpcResultSp type.
941 private RendererRpcResultSp buildNotification(
942 ServicePathNotificationTypes servicePathNotificationTypes,
944 RpcStatusEx rpcStatusEx,
946 PathDescription pathDescription,
948 Set<String> supportedLinks,
949 String serviceType) {
950 RendererRpcResultSpBuilder builder =
951 new RendererRpcResultSpBuilder()
952 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
953 .setStatusMessage(message)
954 .setServiceType(serviceType);
955 if (pathDescription != null) {
957 .setAToZDirection(pathDescription.getAToZDirection())
958 .setZToADirection(pathDescription.getZToADirection());
960 if (notifLink != null) {
961 builder.setLink(notifLink);
963 if (supportedLinks != null) {
964 builder.setLinkId(supportedLinks);
966 return builder.build();
970 * Send renderer notification.
971 * @param notification Notification
973 private void send(Notification<?> notification) {
975 LOG.info("Sending notification {}", notification);
976 notificationPublishService.putNotification(notification);
977 } catch (InterruptedException e) {
978 LOG.info("notification offer rejected: ", e);
979 Thread.currentThread().interrupt();
983 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
985 otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
989 new ATerminationBuilder()
990 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
991 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
994 new ZTerminationBuilder()
995 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
996 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
1001 private Set<String> getSupportedLinks(Set<String> allSupportLinks, String serviceType) {
1002 //TODO a Map might be more indicated here
1003 switch (serviceType) {
1004 case StringConstants.SERVICE_TYPE_10GE:
1005 case StringConstants.SERVICE_TYPE_1GE:
1006 return allSupportLinks.stream()
1007 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toSet());
1008 case StringConstants.SERVICE_TYPE_100GE_M:
1009 return allSupportLinks.stream()
1010 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toSet());
1011 case StringConstants.SERVICE_TYPE_ODU4:
1012 case StringConstants.SERVICE_TYPE_100GE_S:
1013 return allSupportLinks.stream()
1014 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toSet());
1015 case StringConstants.SERVICE_TYPE_ODUC4:
1016 return allSupportLinks.stream()
1017 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toSet());