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.rev190531.ServiceFormat;
66 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.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().getPort() == null
212 || service.getServiceAEnd().getTxDirection().getPort().getPortName() == null
214 : portMapping.getMapping(
215 service.getServiceAEnd().getNodeId().getValue(),
216 service.getServiceAEnd().getTxDirection().getPort().getPortName()));
217 switch (serviceType) {
218 case StringConstants.SERVICE_TYPE_100GE_T:
219 case StringConstants.SERVICE_TYPE_400GE:
220 case StringConstants.SERVICE_TYPE_OTU4:
221 case StringConstants.SERVICE_TYPE_OTUC2:
222 case StringConstants.SERVICE_TYPE_OTUC3:
223 case StringConstants.SERVICE_TYPE_OTUC4:
224 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
225 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
229 case StringConstants.SERVICE_TYPE_1GE:
230 case StringConstants.SERVICE_TYPE_10GE:
231 case StringConstants.SERVICE_TYPE_100GE_M:
232 case StringConstants.SERVICE_TYPE_100GE_S:
233 case StringConstants.SERVICE_TYPE_ODU4:
234 case StringConstants.SERVICE_TYPE_ODUC2:
235 case StringConstants.SERVICE_TYPE_ODUC3:
236 case StringConstants.SERVICE_TYPE_ODUC4:
237 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
238 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
243 LOG.error("unsupported service-type");
244 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
247 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
252 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
253 value = "UPM_UNCALLED_PRIVATE_METHOD",
254 justification = "call in call() method")
255 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
256 if (input.getServiceAEnd() == null) {
257 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
260 if (input.getServiceAEnd().getServiceRate() != null) {
261 return input.getServiceAEnd().getServiceRate();
263 LOG.warn("Input should have rate if you are using 200 or 300G");
264 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
265 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
266 ServiceFormat.OTU, Map.of(
267 "OTUCn", Uint32.valueOf(400),
268 "OTU4", Uint32.valueOf(100),
269 "OTU2", Uint32.valueOf(10),
270 "OTU2e", Uint32.valueOf(10)),
271 ServiceFormat.ODU, Map.of(
272 "ODUCn",Uint32.valueOf(400),
273 "ODU4", Uint32.valueOf(100),
274 "ODU2", Uint32.valueOf(10),
275 "ODU2e", Uint32.valueOf(10),
276 "ODU0", Uint32.valueOf(1)));
277 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
278 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
279 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
283 ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
284 ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
285 : input.getServiceAEnd().getOduServiceRate().getSimpleName();
286 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
287 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
288 input.getServiceName(), serviceName);
291 return formatRateMap.get(input.getServiceAEnd().getServiceFormat()).get(serviceName);
294 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
295 value = "UPM_UNCALLED_PRIVATE_METHOD",
296 justification = "call in call() method")
297 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
298 throws InterruptedException, ExecutionException, TimeoutException {
299 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
300 Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
301 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
302 return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
305 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
306 value = "UPM_UNCALLED_PRIVATE_METHOD",
307 justification = "call in call() method")
308 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
309 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
310 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
311 .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
312 .child(ServicePaths.class, new ServicePathsKey(serviceName))
313 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
314 .service.path.PathDescription.class);
315 ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
317 LOG.debug("Getting path description for service {}", serviceName);
318 return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
319 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
320 } catch (InterruptedException | ExecutionException | TimeoutException e) {
321 LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
323 return Optional.empty();
327 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
328 value = "UPM_UNCALLED_PRIVATE_METHOD",
329 justification = "call in call() method")
330 private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
331 ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
332 LOG.info(RENDERING_DEVICES_A_Z_MSG);
333 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
334 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
335 RENDERING_DEVICES_A_Z_MSG);
336 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
337 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
338 ServicePathDirection.A_TO_Z));
340 LOG.info("Rendering devices Z-A");
341 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
342 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
343 RENDERING_DEVICES_Z_A_MSG);
344 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
345 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
346 ServicePathDirection.Z_TO_A));
347 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
348 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
350 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
352 LOG.info("Waiting for A-Z and Z-A device renderers ...");
353 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
354 } catch (InterruptedException | ExecutionException | TimeoutException e) {
355 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
356 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
357 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
358 DEVICE_RENDERING_ROLL_BACK_MSG);
359 //FIXME we can't do rollback here, because we don't have rendering results.
360 return renderingResults;
363 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
364 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
365 this.deviceRenderer));
366 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
367 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
368 this.deviceRenderer));
369 return renderingResults;
372 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
373 value = "UPM_UNCALLED_PRIVATE_METHOD",
374 justification = "call in call() method")
375 private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
376 OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA, String serviceType) {
377 LOG.info(RENDERING_DEVICES_A_Z_MSG);
378 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
379 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
380 RENDERING_DEVICES_A_Z_MSG);
381 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
382 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
383 LOG.info(RENDERING_DEVICES_Z_A_MSG);
384 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
385 otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
386 RENDERING_DEVICES_Z_A_MSG);
387 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
388 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
389 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
390 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
391 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
393 LOG.info("Waiting for A-Z and Z-A device renderers ...");
394 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
395 } catch (InterruptedException | ExecutionException | TimeoutException e) {
396 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
397 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
398 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
399 DEVICE_RENDERING_ROLL_BACK_MSG);
400 //FIXME we can't do rollback here, because we don't have rendering results.
401 return otnRenderingResults;
403 for (int i = 0; i < otnRenderingResults.size(); i++) {
404 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("DeviceTask n° " + i + 1,
405 ! otnRenderingResults.get(i).isSuccess(), otnRenderingResults.get(i).getRenderedNodeInterfaces(),
406 this.deviceRenderer));
408 return otnRenderingResults;
411 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
412 value = "UPM_UNCALLED_PRIVATE_METHOD",
413 justification = "call in call() method")
414 private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
415 ServicePowerSetupInput powerSetupInputZtoA) {
416 LOG.info("Olm power setup A-Z");
417 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
418 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
419 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
420 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
422 LOG.info("OLM power setup Z-A");
423 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
424 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
425 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
426 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
427 ListenableFuture<List<OLMRenderingResult>> olmFutures =
428 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
430 List<OLMRenderingResult> olmResults;
432 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
433 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
434 } catch (InterruptedException | ExecutionException | TimeoutException e) {
435 LOG.warn(OLM_ROLL_BACK_MSG, e);
436 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
437 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
439 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
440 this.olmService, powerSetupInputAtoZ));
441 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
442 this.olmService, powerSetupInputZtoA));
446 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
447 this.olmService, powerSetupInputAtoZ));
448 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
449 this.olmService, powerSetupInputZtoA));
452 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
453 value = "UPM_UNCALLED_PRIVATE_METHOD",
454 justification = "call in call() method")
455 private boolean isServiceActivated(String nodeId, String tpId) {
456 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
457 for (int i = 0; i < 3; i++) {
458 List<Measurements> measurements = getMeasurements(nodeId, tpId);
459 if (measurements == null) {
460 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
463 if (verifyPreFecBer(measurements)) {
467 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
468 } catch (InterruptedException ex) {
469 Thread.currentThread().interrupt();
472 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
476 private List<Measurements> getMeasurements(String nodeId, String tp) {
477 GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder()
479 .setGranularity(PmGranularity._15min)
480 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
481 .setResourceType(ResourceTypeEnum.Interface);
484 Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
485 RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
486 GetPmOutput getPmOutput = getPmRpcResult.getResult();
487 if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
488 LOG.info("successfully finished calling OLM's get PM");
489 return getPmOutput.getMeasurements();
492 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
495 } catch (ExecutionException | InterruptedException e) {
496 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
501 private boolean verifyPreFecBer(List<Measurements> measurements) {
502 double preFecCorrectedErrors = Double.MIN_VALUE;
503 double fecUncorrectableBlocks = Double.MIN_VALUE;
505 for (Measurements measurement : measurements) {
506 switch (measurement.getPmparameterName()) {
507 case "preFECCorrectedErrors":
508 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
510 case "FECUncorrectableBlocks":
511 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
518 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
519 fecUncorrectableBlocks);
521 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
522 LOG.error("Data has uncorrectable errors, BER test failed");
526 double numOfBitsPerSecond = 112000000000d;
527 double threshold = 0.00002d;
528 double result = preFecCorrectedErrors / numOfBitsPerSecond;
529 LOG.info("PreFEC value is {}", Double.toString(result));
530 return result <= threshold;
533 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
534 value = "UPM_UNCALLED_PRIVATE_METHOD",
535 justification = "call in call() method")
536 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
537 ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
538 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
539 ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
540 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
541 // Rollback should be same for all conditions, so creating a new one
542 RollbackProcessor rollbackProcessor = new RollbackProcessor();
543 List<DeviceRenderingResult> renderingResults =
544 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
545 if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
546 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
547 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
550 ServicePowerSetupInput olmPowerSetupInputAtoZ =
551 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
552 ServicePowerSetupInput olmPowerSetupInputZtoA =
553 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
554 olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
555 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
556 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
557 input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
560 // run service activation test twice - once on source node and once on
562 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
563 if ((nodes == null) || (nodes.isEmpty())) {
567 Nodes sourceNode = nodes.get(0);
568 Nodes destNode = nodes.get(nodes.size() - 1);
569 String srcNetworkTp =
570 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
571 ? sourceNode.getDestTp()
572 : sourceNode.getSrcTp();
573 String dstNetowrkTp =
574 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
575 ? destNode.getDestTp()
576 : destNode.getSrcTp();
578 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
579 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
580 rollbackProcessor.rollbackAll();
581 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
582 input.getServiceName(), RpcStatusEx.Failed,
583 "Service activation test failed.");
586 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
587 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
588 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
590 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
591 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
592 notifLink, null, serviceType);
596 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
597 value = "UPM_UNCALLED_PRIVATE_METHOD",
598 justification = "call in call() method")
599 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
600 throws InterruptedException {
601 ServicePathInputData servicePathInputDataAtoZ =
602 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
603 ServicePathInputData servicePathInputDataZtoA =
604 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
605 // OLM turn down power
607 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
608 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
609 RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
610 ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
611 // TODO add some flag rather than string
612 if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
613 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
614 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
615 "Service power turndown failed on A-to-Z path for service");
618 LOG.debug("Turning down power on Z-to-A path");
619 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
620 "Turning down power on Z-to-A path");
621 ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
622 // TODO add some flag rather than string
623 if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
624 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
625 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
626 "Service power turndown failed on Z-to-A path for service");
629 } catch (InterruptedException | ExecutionException | TimeoutException e) {
630 LOG.error("Error while turning down power!", e);
633 // delete service path with renderer
634 LOG.info("Deleting service path via renderer");
635 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
636 "Deleting service path via renderer");
637 RollbackProcessor rollbackProcessor = new RollbackProcessor();
638 List<DeviceRenderingResult> renderingResults =
639 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
640 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
641 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
642 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
644 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
645 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, null, serviceType);
649 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
650 value = "UPM_UNCALLED_PRIVATE_METHOD",
651 justification = "call in call() method")
652 private boolean manageOtnServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
653 Uint32 serviceRate) {
655 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
656 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
657 input.getServiceAEnd().getServiceFormat().getName(),
659 input.getPathDescription(), true);
661 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
662 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
663 input.getServiceZEnd().getServiceFormat().getName(),
665 input.getPathDescription(), false);
666 // Rollback should be same for all conditions, so creating a new one
667 RollbackProcessor rollbackProcessor = new RollbackProcessor();
668 List<OtnDeviceRenderingResult> renderingResults =
669 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
670 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
671 rollbackProcessor.rollbackAll();
672 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
673 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
676 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
677 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
678 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
679 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription());
680 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
682 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
683 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
684 notifLink, supportedLinks, serviceType);
688 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
689 value = "UPM_UNCALLED_PRIVATE_METHOD",
690 justification = "call in call() method")
691 private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
692 Services service, String serviceType) {
694 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
695 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
696 service.getServiceAEnd().getServiceFormat().getName(),
697 service.getServiceAEnd().getServiceRate(),
698 pathDescription, true);
700 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
701 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
702 service.getServiceZEnd().getServiceFormat().getName(),
703 service.getServiceAEnd().getServiceRate(),
704 pathDescription, false);
705 LOG.info("Deleting otn-service path {} via renderer", serviceName);
706 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
707 "Deleting otn-service path via renderer");
709 RollbackProcessor rollbackProcessor = new RollbackProcessor();
710 List<OtnDeviceRenderingResult> renderingResults =
711 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
713 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
714 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
715 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
716 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(pathDescription);
717 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
719 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
720 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, supportedLinks,
726 * Send renderer notification.
727 * @param servicePathNotificationTypes ServicePathNotificationTypes
728 * @param serviceName String
729 * @param rpcStatusEx RpcStatusEx
730 * @param message String
732 private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
733 RpcStatusEx rpcStatusEx, String message) {
734 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
735 null, null, null, null);
740 * Send renderer notification with path description information.
741 * @param servicePathNotificationTypes ServicePathNotificationTypes
742 * @param serviceName String
743 * @param rpcStatusEx RpcStatusEx
744 * @param message String
745 * @param pathDescription PathDescription
747 private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
748 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
749 Link notifLink, List<String> supportedLinks, String serviceType) {
750 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
751 pathDescription, notifLink, supportedLinks, serviceType);
756 * Build notification containing path description information.
757 * @param servicePathNotificationTypes ServicePathNotificationTypes
758 * @param serviceName String
759 * @param rpcStatusEx RpcStatusEx
760 * @param message String
761 * @param pathDescription PathDescription
762 * @return notification with RendererRpcResultSp type.
764 private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
765 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
766 Link notifLink, List<String> supportedLinks, String serviceType) {
767 RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
768 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
769 .setStatusMessage(message)
770 .setServiceType(serviceType);
771 if (pathDescription != null) {
772 builder.setAToZDirection(pathDescription.getAToZDirection())
773 .setZToADirection(pathDescription.getZToADirection());
775 if (notifLink != null) {
776 builder.setLink(notifLink);
778 if (supportedLinks != null) {
779 builder.setLinkId(supportedLinks);
781 return builder.build();
785 * Send renderer notification.
786 * @param notification Notification
788 private void send(Notification notification) {
790 LOG.info("Sending notification {}", notification);
791 notificationPublishService.putNotification(notification);
792 } catch (InterruptedException e) {
793 LOG.info("notification offer rejected: ", e);
794 Thread.currentThread().interrupt();
798 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
799 if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
802 return new LinkBuilder()
803 .setATermination(new ATerminationBuilder()
804 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
805 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
807 .setZTermination(new ZTerminationBuilder()
808 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
809 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
814 private List<String> getSupportedLinks(List<String> allSupportLinks, String serviceType) {
815 switch (serviceType) {
816 case StringConstants.SERVICE_TYPE_10GE:
817 case StringConstants.SERVICE_TYPE_1GE:
818 return allSupportLinks.stream()
819 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toList());
820 case StringConstants.SERVICE_TYPE_100GE_M:
821 return allSupportLinks.stream()
822 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toList());
823 case StringConstants.SERVICE_TYPE_ODU4:
824 case StringConstants.SERVICE_TYPE_100GE_S:
825 return allSupportLinks.stream()
826 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
827 case StringConstants.SERVICE_TYPE_ODUC4:
828 return allSupportLinks.stream()
829 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());