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.renderer.rev210915.RendererRpcResultSp;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSpBuilder;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
61 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
62 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
63 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
66 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.PathDescription;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.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.rev210930.link.tp.LinkTp;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.olm.get.pm.input.ResourceIdentifierBuilder;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.optical.renderer.nodes.Nodes;
76 import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev220123.OtnLinkType;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.binding.Notification;
79 import org.opendaylight.yangtools.yang.common.RpcResult;
80 import org.opendaylight.yangtools.yang.common.Uint32;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
85 public class RendererServiceOperationsImpl implements RendererServiceOperations {
87 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
88 "Device rendering was not successful! Rendering will be rolled back.";
89 private static final String OLM_ROLL_BACK_MSG =
90 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
91 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
92 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
93 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
94 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
95 private static final String FAILED = "Failed";
96 private static final String OPERATION_FAILED = "Operation Failed";
97 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
98 private static final int NUMBER_OF_THREADS = 4;
100 private final DeviceRendererService deviceRenderer;
101 private final OtnDeviceRendererService otnDeviceRenderer;
102 private final TransportpceOlmService olmService;
103 private final DataBroker dataBroker;
104 private final NotificationPublishService notificationPublishService;
105 private final PortMapping portMapping;
106 private ListeningExecutorService executor;
108 public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
109 OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
110 DataBroker dataBroker, NotificationPublishService notificationPublishService, PortMapping portMapping) {
111 this.deviceRenderer = deviceRenderer;
112 this.otnDeviceRenderer = otnDeviceRenderer;
113 this.olmService = olmService;
114 this.dataBroker = dataBroker;
115 this.notificationPublishService = notificationPublishService;
116 this.portMapping = portMapping;
117 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
121 public ListenableFuture<ServiceImplementationRequestOutput>
122 serviceImplementation(ServiceImplementationRequestInput input) {
123 LOG.info("Calling service impl request {}", input.getServiceName());
124 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
127 public ServiceImplementationRequestOutput call() throws Exception {
128 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
129 RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
130 Uint32 serviceRate = getServiceRate(input);
131 LOG.info("Using {}G rate", serviceRate);
132 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220114.network.Nodes
133 mappingNode = portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
134 ? portMapping.getNode(input.getServiceAEnd().getNodeId())
136 String serviceType = ServiceTypes.getServiceType(
137 input.getServiceAEnd().getServiceFormat().getName(),
140 && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
141 && input.getServiceAEnd().getTxDirection() != null
142 && input.getServiceAEnd().getTxDirection().getPort() != null
143 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null)
144 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
145 input.getServiceAEnd().getTxDirection().getPort().getPortName())
148 switch (serviceType) {
149 case StringConstants.SERVICE_TYPE_100GE_T:
150 case StringConstants.SERVICE_TYPE_400GE:
151 case StringConstants.SERVICE_TYPE_OTU4:
152 case StringConstants.SERVICE_TYPE_OTUC2:
153 case StringConstants.SERVICE_TYPE_OTUC3:
154 case StringConstants.SERVICE_TYPE_OTUC4:
155 if (!manageServicePathCreation(input, serviceType)) {
156 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
160 case StringConstants.SERVICE_TYPE_1GE:
161 case StringConstants.SERVICE_TYPE_10GE:
162 case StringConstants.SERVICE_TYPE_100GE_M:
163 case StringConstants.SERVICE_TYPE_100GE_S:
164 case StringConstants.SERVICE_TYPE_ODU4:
165 case StringConstants.SERVICE_TYPE_ODUC2:
166 case StringConstants.SERVICE_TYPE_ODUC3:
167 case StringConstants.SERVICE_TYPE_ODUC4:
168 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
169 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
174 LOG.error("unsupported service-type");
175 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
178 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
179 OPERATION_SUCCESSFUL);
185 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
186 String serviceName = input.getServiceName();
187 LOG.info("Calling service delete request {}", serviceName);
188 return executor.submit(new Callable<ServiceDeleteOutput>() {
191 public ServiceDeleteOutput call() throws Exception {
192 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
193 RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
194 // Obtain path description
196 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service
197 .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
198 if (pathDescriptionOpt.isEmpty()) {
199 LOG.error("Unable to get path description for service {}!", serviceName);
200 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
201 RpcStatusEx.Failed, "Unable to get path description for service");
202 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
205 PathDescription pathDescription = pathDescriptionOpt.get();
207 ServiceTypes.getServiceType(
208 service.getServiceAEnd().getServiceFormat().getName(),
209 service.getServiceAEnd().getServiceRate(),
210 service.getServiceAEnd().getTxDirection() == null
211 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
213 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
214 .getPort().getPortName() == null
216 : portMapping.getMapping(
217 service.getServiceAEnd().getNodeId().getValue(),
218 service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
219 .getPort().getPortName()));
220 switch (serviceType) {
221 case StringConstants.SERVICE_TYPE_100GE_T:
222 case StringConstants.SERVICE_TYPE_400GE:
223 case StringConstants.SERVICE_TYPE_OTU4:
224 case StringConstants.SERVICE_TYPE_OTUC2:
225 case StringConstants.SERVICE_TYPE_OTUC3:
226 case StringConstants.SERVICE_TYPE_OTUC4:
227 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
228 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
232 case StringConstants.SERVICE_TYPE_1GE:
233 case StringConstants.SERVICE_TYPE_10GE:
234 case StringConstants.SERVICE_TYPE_100GE_M:
235 case StringConstants.SERVICE_TYPE_100GE_S:
236 case StringConstants.SERVICE_TYPE_ODU4:
237 case StringConstants.SERVICE_TYPE_ODUC2:
238 case StringConstants.SERVICE_TYPE_ODUC3:
239 case StringConstants.SERVICE_TYPE_ODUC4:
240 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
241 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
246 LOG.error("unsupported service-type");
247 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
250 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
255 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
256 value = "UPM_UNCALLED_PRIVATE_METHOD",
257 justification = "call in call() method")
258 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
259 if (input.getServiceAEnd() == null) {
260 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
263 if (input.getServiceAEnd().getServiceRate() != null) {
264 return input.getServiceAEnd().getServiceRate();
266 LOG.warn("Input should have rate if you are using 200 or 300G");
267 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
268 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
269 ServiceFormat.OTU, Map.of(
270 "OTUCn", Uint32.valueOf(400),
271 "OTU4", Uint32.valueOf(100),
272 "OTU2", Uint32.valueOf(10),
273 "OTU2e", Uint32.valueOf(10)),
274 ServiceFormat.ODU, Map.of(
275 "ODUCn",Uint32.valueOf(400),
276 "ODU4", Uint32.valueOf(100),
277 "ODU2", Uint32.valueOf(10),
278 "ODU2e", Uint32.valueOf(10),
279 "ODU0", Uint32.valueOf(1)));
280 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
281 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
282 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
286 ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
287 ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
288 : input.getServiceAEnd().getOduServiceRate().getSimpleName();
289 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
290 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
291 input.getServiceName(), serviceName);
294 return formatRateMap.get(input.getServiceAEnd().getServiceFormat()).get(serviceName);
297 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
298 value = "UPM_UNCALLED_PRIVATE_METHOD",
299 justification = "call in call() method")
300 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
301 throws InterruptedException, ExecutionException, TimeoutException {
302 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
303 Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
304 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
305 return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
308 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
309 value = "UPM_UNCALLED_PRIVATE_METHOD",
310 justification = "call in call() method")
311 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
312 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
313 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
314 .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
315 .child(ServicePaths.class, new ServicePathsKey(serviceName))
316 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
317 .service.path.PathDescription.class);
318 ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
320 LOG.debug("Getting path description for service {}", serviceName);
321 return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
322 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
323 } catch (InterruptedException | ExecutionException | TimeoutException e) {
324 LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
326 return Optional.empty();
330 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
331 value = "UPM_UNCALLED_PRIVATE_METHOD",
332 justification = "call in call() method")
333 private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
334 ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
335 LOG.info(RENDERING_DEVICES_A_Z_MSG);
336 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
337 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
338 RENDERING_DEVICES_A_Z_MSG);
339 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
340 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
341 ServicePathDirection.A_TO_Z));
343 LOG.info("Rendering devices Z-A");
344 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
345 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
346 RENDERING_DEVICES_Z_A_MSG);
347 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
348 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
349 ServicePathDirection.Z_TO_A));
350 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
351 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
353 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
355 LOG.info("Waiting for A-Z and Z-A device renderers ...");
356 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
357 } catch (InterruptedException | ExecutionException | TimeoutException e) {
358 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
359 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
360 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
361 DEVICE_RENDERING_ROLL_BACK_MSG);
362 //FIXME we can't do rollback here, because we don't have rendering results.
363 return renderingResults;
366 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
367 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
368 this.deviceRenderer));
369 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
370 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
371 this.deviceRenderer));
372 return renderingResults;
375 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
376 value = "UPM_UNCALLED_PRIVATE_METHOD",
377 justification = "call in call() method")
378 private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
379 OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA, String serviceType) {
380 LOG.info(RENDERING_DEVICES_A_Z_MSG);
381 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
382 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
383 RENDERING_DEVICES_A_Z_MSG);
384 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
385 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
386 LOG.info(RENDERING_DEVICES_Z_A_MSG);
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, serviceType));
392 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
393 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
394 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
396 LOG.info("Waiting for A-Z and Z-A device renderers ...");
397 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
398 } catch (InterruptedException | ExecutionException | TimeoutException e) {
399 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
400 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
401 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
402 DEVICE_RENDERING_ROLL_BACK_MSG);
403 //FIXME we can't do rollback here, because we don't have rendering results.
404 return otnRenderingResults;
406 for (int i = 0; i < otnRenderingResults.size(); i++) {
407 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("DeviceTask n° " + i + 1,
408 ! otnRenderingResults.get(i).isSuccess(), otnRenderingResults.get(i).getRenderedNodeInterfaces(),
409 this.deviceRenderer));
411 return otnRenderingResults;
414 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
415 value = "UPM_UNCALLED_PRIVATE_METHOD",
416 justification = "call in call() method")
417 private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
418 ServicePowerSetupInput powerSetupInputZtoA) {
419 LOG.info("Olm power setup A-Z");
420 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
421 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
422 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
423 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
425 LOG.info("OLM power setup Z-A");
426 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
427 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
428 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
429 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
430 ListenableFuture<List<OLMRenderingResult>> olmFutures =
431 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
433 List<OLMRenderingResult> olmResults;
435 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
436 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
437 } catch (InterruptedException | ExecutionException | TimeoutException e) {
438 LOG.warn(OLM_ROLL_BACK_MSG, e);
439 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
440 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
442 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
443 this.olmService, powerSetupInputAtoZ));
444 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
445 this.olmService, powerSetupInputZtoA));
449 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
450 this.olmService, powerSetupInputAtoZ));
451 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
452 this.olmService, powerSetupInputZtoA));
455 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
456 value = "UPM_UNCALLED_PRIVATE_METHOD",
457 justification = "call in call() method")
458 private boolean isServiceActivated(String nodeId, String tpId) {
459 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
460 for (int i = 0; i < 3; i++) {
461 List<Measurements> measurements = getMeasurements(nodeId, tpId);
462 if (measurements == null) {
463 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
466 if (verifyPreFecBer(measurements)) {
470 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
471 } catch (InterruptedException ex) {
472 Thread.currentThread().interrupt();
475 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
479 private List<Measurements> getMeasurements(String nodeId, String tp) {
480 GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder()
482 .setGranularity(PmGranularity._15min)
483 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
484 .setResourceType(ResourceTypeEnum.Interface);
487 Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
488 RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
489 GetPmOutput getPmOutput = getPmRpcResult.getResult();
490 if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
491 LOG.info("successfully finished calling OLM's get PM");
492 return getPmOutput.getMeasurements();
495 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
498 } catch (ExecutionException | InterruptedException e) {
499 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
504 private boolean verifyPreFecBer(List<Measurements> measurements) {
505 double preFecCorrectedErrors = Double.MIN_VALUE;
506 double fecUncorrectableBlocks = Double.MIN_VALUE;
508 for (Measurements measurement : measurements) {
509 switch (measurement.getPmparameterName()) {
510 case "preFECCorrectedErrors":
511 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
513 case "FECUncorrectableBlocks":
514 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
521 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
522 fecUncorrectableBlocks);
524 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
525 LOG.error("Data has uncorrectable errors, BER test failed");
529 double numOfBitsPerSecond = 112000000000d;
530 double threshold = 0.00002d;
531 double result = preFecCorrectedErrors / numOfBitsPerSecond;
532 LOG.info("PreFEC value is {}", Double.toString(result));
533 return result <= threshold;
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, String serviceType) {
540 ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
541 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
542 ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
543 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
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 || renderingResults.isEmpty()) {
549 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
550 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
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);
563 // run service activation test twice - once on source node and once on
565 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
566 if ((nodes == null) || (nodes.isEmpty())) {
570 Nodes sourceNode = nodes.get(0);
571 Nodes destNode = nodes.get(nodes.size() - 1);
572 String srcNetworkTp =
573 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
574 ? sourceNode.getDestTp()
575 : sourceNode.getSrcTp();
576 String dstNetowrkTp =
577 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
578 ? destNode.getDestTp()
579 : destNode.getSrcTp();
581 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
582 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
583 rollbackProcessor.rollbackAll();
584 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
585 input.getServiceName(), RpcStatusEx.Failed,
586 "Service activation test failed.");
589 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
590 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
591 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
593 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
594 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
595 notifLink, null, serviceType);
599 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
600 value = "UPM_UNCALLED_PRIVATE_METHOD",
601 justification = "call in call() method")
602 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
603 throws InterruptedException {
604 ServicePathInputData servicePathInputDataAtoZ =
605 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
606 ServicePathInputData servicePathInputDataZtoA =
607 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
608 // OLM turn down power
610 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
611 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
612 RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
613 ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
614 // TODO add some flag rather than string
615 if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
616 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
617 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
618 "Service power turndown failed on A-to-Z path for service");
621 LOG.debug("Turning down power on Z-to-A path");
622 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
623 "Turning down power on Z-to-A path");
624 ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
625 // TODO add some flag rather than string
626 if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
627 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
628 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
629 "Service power turndown failed on Z-to-A path for service");
632 } catch (InterruptedException | ExecutionException | TimeoutException e) {
633 LOG.error("Error while turning down power!", e);
636 // delete service path with renderer
637 LOG.info("Deleting service path via renderer");
638 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
639 "Deleting service path via renderer");
640 RollbackProcessor rollbackProcessor = new RollbackProcessor();
641 List<DeviceRenderingResult> renderingResults =
642 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
643 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
644 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
645 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
647 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
648 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, null, serviceType);
652 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
653 value = "UPM_UNCALLED_PRIVATE_METHOD",
654 justification = "call in call() method")
655 private boolean manageOtnServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
656 Uint32 serviceRate) {
658 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
659 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
660 input.getServiceAEnd().getServiceFormat().getName(),
662 input.getPathDescription(), true);
664 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
665 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
666 input.getServiceZEnd().getServiceFormat().getName(),
668 input.getPathDescription(), false);
669 // Rollback should be same for all conditions, so creating a new one
670 RollbackProcessor rollbackProcessor = new RollbackProcessor();
671 List<OtnDeviceRenderingResult> renderingResults =
672 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
673 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
674 rollbackProcessor.rollbackAll();
675 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
676 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
679 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
680 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
681 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
682 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription());
683 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
685 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
686 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
687 notifLink, supportedLinks, serviceType);
691 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
692 value = "UPM_UNCALLED_PRIVATE_METHOD",
693 justification = "call in call() method")
694 private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
695 Services service, String serviceType) {
697 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
698 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
699 service.getServiceAEnd().getServiceFormat().getName(),
700 service.getServiceAEnd().getServiceRate(),
701 pathDescription, true);
703 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
704 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
705 service.getServiceZEnd().getServiceFormat().getName(),
706 service.getServiceAEnd().getServiceRate(),
707 pathDescription, false);
708 LOG.info("Deleting otn-service path {} via renderer", serviceName);
709 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
710 "Deleting otn-service path via renderer");
712 RollbackProcessor rollbackProcessor = new RollbackProcessor();
713 List<OtnDeviceRenderingResult> renderingResults =
714 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
716 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
717 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
718 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
719 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(pathDescription);
720 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
722 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
723 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, supportedLinks,
729 * Send renderer notification.
730 * @param servicePathNotificationTypes ServicePathNotificationTypes
731 * @param serviceName String
732 * @param rpcStatusEx RpcStatusEx
733 * @param message String
735 private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
736 RpcStatusEx rpcStatusEx, String message) {
737 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
738 null, null, null, null);
743 * Send renderer notification with path description information.
744 * @param servicePathNotificationTypes ServicePathNotificationTypes
745 * @param serviceName String
746 * @param rpcStatusEx RpcStatusEx
747 * @param message String
748 * @param pathDescription PathDescription
750 private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
751 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
752 Link notifLink, List<String> supportedLinks, String serviceType) {
753 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
754 pathDescription, notifLink, supportedLinks, serviceType);
759 * Build notification containing path description information.
760 * @param servicePathNotificationTypes ServicePathNotificationTypes
761 * @param serviceName String
762 * @param rpcStatusEx RpcStatusEx
763 * @param message String
764 * @param pathDescription PathDescription
765 * @return notification with RendererRpcResultSp type.
767 private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
768 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
769 Link notifLink, List<String> supportedLinks, String serviceType) {
770 RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
771 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
772 .setStatusMessage(message)
773 .setServiceType(serviceType);
774 if (pathDescription != null) {
775 builder.setAToZDirection(pathDescription.getAToZDirection())
776 .setZToADirection(pathDescription.getZToADirection());
778 if (notifLink != null) {
779 builder.setLink(notifLink);
781 if (supportedLinks != null) {
782 builder.setLinkId(supportedLinks);
784 return builder.build();
788 * Send renderer notification.
789 * @param notification Notification
791 private void send(Notification notification) {
793 LOG.info("Sending notification {}", notification);
794 notificationPublishService.putNotification(notification);
795 } catch (InterruptedException e) {
796 LOG.info("notification offer rejected: ", e);
797 Thread.currentThread().interrupt();
801 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
802 if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
805 return new LinkBuilder()
806 .setATermination(new ATerminationBuilder()
807 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
808 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
810 .setZTermination(new ZTerminationBuilder()
811 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
812 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
817 private List<String> getSupportedLinks(List<String> allSupportLinks, String serviceType) {
818 switch (serviceType) {
819 case StringConstants.SERVICE_TYPE_10GE:
820 case StringConstants.SERVICE_TYPE_1GE:
821 return allSupportLinks.stream()
822 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toList());
823 case StringConstants.SERVICE_TYPE_100GE_M:
824 return allSupportLinks.stream()
825 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toList());
826 case StringConstants.SERVICE_TYPE_ODU4:
827 case StringConstants.SERVICE_TYPE_100GE_S:
828 return allSupportLinks.stream()
829 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
830 case StringConstants.SERVICE_TYPE_ODUC4:
831 return allSupportLinks.stream()
832 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());