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.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 import java.util.stream.Collectors;
24 import org.opendaylight.mdsal.binding.api.DataBroker;
25 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.transportpce.common.ResponseCodes;
28 import org.opendaylight.transportpce.common.StringConstants;
29 import org.opendaylight.transportpce.common.Timeouts;
30 import org.opendaylight.transportpce.common.mapping.PortMapping;
31 import org.opendaylight.transportpce.common.service.ServiceTypes;
32 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
33 import org.opendaylight.transportpce.renderer.ServicePathInputData;
34 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
35 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
36 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownInputBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSp;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSpBuilder;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
60 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
61 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
62 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
63 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
65 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.PathDescription;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.link.tp.LinkTp;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.olm.get.pm.input.ResourceIdentifierBuilder;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.optical.renderer.nodes.Nodes;
74 import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev220123.OtnLinkType;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.binding.Notification;
77 import org.opendaylight.yangtools.yang.common.Uint32;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
82 public class RendererServiceOperationsImpl implements RendererServiceOperations {
84 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
85 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
86 "Device rendering was not successful! Rendering will be rolled back.";
87 private static final String OLM_ROLL_BACK_MSG =
88 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
89 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
90 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
91 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
92 private static final String FAILED = "Failed";
93 private static final String OPERATION_FAILED = "Operation Failed";
94 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
95 private static final int NUMBER_OF_THREADS = 4;
97 private final DeviceRendererService deviceRenderer;
98 private final OtnDeviceRendererService otnDeviceRenderer;
99 private final TransportpceOlmService olmService;
100 private final DataBroker dataBroker;
101 private final NotificationPublishService notificationPublishService;
102 private final PortMapping portMapping;
103 private ListeningExecutorService executor;
105 public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
106 OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
107 DataBroker dataBroker, NotificationPublishService notificationPublishService, PortMapping portMapping) {
108 this.deviceRenderer = deviceRenderer;
109 this.otnDeviceRenderer = otnDeviceRenderer;
110 this.olmService = olmService;
111 this.dataBroker = dataBroker;
112 this.notificationPublishService = notificationPublishService;
113 this.portMapping = portMapping;
114 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
118 public ListenableFuture<ServiceImplementationRequestOutput>
119 serviceImplementation(ServiceImplementationRequestInput input) {
120 LOG.info("Calling service impl request {}", input.getServiceName());
121 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
124 public ServiceImplementationRequestOutput call() throws Exception {
126 ServicePathNotificationTypes.ServiceImplementationRequest,
127 input.getServiceName(),
129 "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.rev220316
133 .network.Nodes mappingNode =
134 portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
135 ? portMapping.getNode(input.getServiceAEnd().getNodeId())
137 String serviceType = ServiceTypes.getServiceType(
138 input.getServiceAEnd().getServiceFormat().getName(),
141 && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
142 && input.getServiceAEnd().getTxDirection() != null
143 && input.getServiceAEnd().getTxDirection().getPort() != null
144 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
145 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
146 input.getServiceAEnd().getTxDirection().getPort().getPortName())
148 //TODO a Map might be more indicated here
149 switch (serviceType) {
150 case StringConstants.SERVICE_TYPE_100GE_T:
151 case StringConstants.SERVICE_TYPE_400GE:
152 case StringConstants.SERVICE_TYPE_OTU4:
153 case StringConstants.SERVICE_TYPE_OTUC2:
154 case StringConstants.SERVICE_TYPE_OTUC3:
155 case StringConstants.SERVICE_TYPE_OTUC4:
156 if (!manageServicePathCreation(input, serviceType)) {
157 return ModelMappingUtils
158 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
161 case StringConstants.SERVICE_TYPE_1GE:
162 case StringConstants.SERVICE_TYPE_10GE:
163 case StringConstants.SERVICE_TYPE_100GE_M:
164 case StringConstants.SERVICE_TYPE_100GE_S:
165 case StringConstants.SERVICE_TYPE_ODU4:
166 case StringConstants.SERVICE_TYPE_ODUC2:
167 case StringConstants.SERVICE_TYPE_ODUC3:
168 case StringConstants.SERVICE_TYPE_ODUC4:
169 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
170 return ModelMappingUtils
171 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
175 LOG.error("unsupported service-type");
176 return ModelMappingUtils
177 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
179 return ModelMappingUtils
180 .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
186 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
187 String serviceName = input.getServiceName();
188 LOG.info("Calling service delete request {}", serviceName);
189 return executor.submit(new Callable<ServiceDeleteOutput>() {
192 public ServiceDeleteOutput call() throws Exception {
194 ServicePathNotificationTypes.ServiceDelete,
197 "Service compliant, submitting service delete Request ...");
198 // Obtain path description
200 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
201 .service.path.PathDescription> pathDescriptionOpt =
202 getPathDescriptionFromDatastore(serviceName);
203 if (pathDescriptionOpt.isEmpty()) {
204 LOG.error("Unable to get path description for service {}!", serviceName);
206 ServicePathNotificationTypes.ServiceDelete,
209 "Unable to get path description for service");
210 return ModelMappingUtils
211 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
213 PathDescription pathDescription = pathDescriptionOpt.get();
215 ServiceTypes.getServiceType(
216 service.getServiceAEnd().getServiceFormat().getName(),
217 service.getServiceAEnd().getServiceRate(),
218 service.getServiceAEnd().getTxDirection() == null
219 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
221 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
222 .getPort().getPortName() == null
224 : portMapping.getMapping(
225 service.getServiceAEnd().getNodeId().getValue(),
226 service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
227 .getPort().getPortName()));
228 switch (serviceType) {
229 case StringConstants.SERVICE_TYPE_100GE_T:
230 case StringConstants.SERVICE_TYPE_400GE:
231 case StringConstants.SERVICE_TYPE_OTU4:
232 case StringConstants.SERVICE_TYPE_OTUC2:
233 case StringConstants.SERVICE_TYPE_OTUC3:
234 case StringConstants.SERVICE_TYPE_OTUC4:
235 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
236 return ModelMappingUtils
237 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
240 case StringConstants.SERVICE_TYPE_1GE:
241 case StringConstants.SERVICE_TYPE_10GE:
242 case StringConstants.SERVICE_TYPE_100GE_M:
243 case StringConstants.SERVICE_TYPE_100GE_S:
244 case StringConstants.SERVICE_TYPE_ODU4:
245 case StringConstants.SERVICE_TYPE_ODUC2:
246 case StringConstants.SERVICE_TYPE_ODUC3:
247 case StringConstants.SERVICE_TYPE_ODUC4:
248 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
249 return ModelMappingUtils
250 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
254 LOG.error("unsupported service-type");
255 return ModelMappingUtils
256 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
258 return ModelMappingUtils
259 .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
264 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
265 value = "UPM_UNCALLED_PRIVATE_METHOD",
266 justification = "call in call() method")
267 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
268 if (input.getServiceAEnd() == null) {
269 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
272 if (input.getServiceAEnd().getServiceRate() != null) {
273 return input.getServiceAEnd().getServiceRate();
275 LOG.warn("Input should have rate if you are using 200 or 300G");
276 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
277 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
278 ServiceFormat.OTU, Map.of(
279 "OTUCn", Uint32.valueOf(400),
280 "OTU4", Uint32.valueOf(100),
281 "OTU2", Uint32.valueOf(10),
282 "OTU2e", Uint32.valueOf(10)),
283 ServiceFormat.ODU, Map.of(
284 "ODUCn",Uint32.valueOf(400),
285 "ODU4", Uint32.valueOf(100),
286 "ODU2", Uint32.valueOf(10),
287 "ODU2e", Uint32.valueOf(10),
288 "ODU0", Uint32.valueOf(1)));
289 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
290 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
291 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
295 ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
296 ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
297 : input.getServiceAEnd().getOduServiceRate().getSimpleName();
298 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
299 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
300 input.getServiceName(), serviceName);
304 .get(input.getServiceAEnd().getServiceFormat())
308 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
309 value = "UPM_UNCALLED_PRIVATE_METHOD",
310 justification = "call in call() method")
311 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
312 throws InterruptedException, ExecutionException, TimeoutException {
313 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
314 return this.olmService
315 .servicePowerTurndown(
316 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build())
317 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS)
321 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
322 value = "UPM_UNCALLED_PRIVATE_METHOD",
323 justification = "call in call() method")
324 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
325 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
326 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
327 .service.path.PathDescription> pathDescriptionIID =
328 InstanceIdentifier.create(ServicePathList.class)
329 .child(ServicePaths.class, new ServicePathsKey(serviceName))
330 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
331 .service.path.PathDescription.class);
333 LOG.debug("Getting path description for service {}", serviceName);
334 return this.dataBroker.newReadOnlyTransaction()
335 .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
336 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
337 } catch (InterruptedException | ExecutionException | TimeoutException e) {
338 LOG.warn("Exception while getting path description from datastore {} for service {}!",
339 pathDescriptionIID, serviceName, e);
340 return Optional.empty();
344 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
345 value = "UPM_UNCALLED_PRIVATE_METHOD",
346 justification = "call in call() method")
347 private List<DeviceRenderingResult> deviceRendering(
348 RollbackProcessor rollbackProcessor,
349 ServicePathInputData servicePathDataAtoZ,
350 ServicePathInputData servicePathDataZtoA) {
352 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
353 // Do notifications & LOG.info deserve this ?
354 LOG.info(RENDERING_DEVICES_A_Z_MSG);
356 ServicePathNotificationTypes.ServiceImplementationRequest,
357 servicePathDataAtoZ.getServicePathInput().getServiceName(),
359 RENDERING_DEVICES_A_Z_MSG);
360 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
361 this.executor.submit(
362 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z));
364 LOG.info(RENDERING_DEVICES_Z_A_MSG);
366 ServicePathNotificationTypes.ServiceImplementationRequest,
367 servicePathDataZtoA.getServicePathInput().getServiceName(),
369 RENDERING_DEVICES_Z_A_MSG);
370 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
371 this.executor.submit(
372 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A));
374 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
375 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
377 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
379 LOG.info("Waiting for A-Z and Z-A device renderers ...");
380 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
381 } catch (InterruptedException | ExecutionException | TimeoutException e) {
382 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
384 ServicePathNotificationTypes.ServiceImplementationRequest,
385 servicePathDataAtoZ.getServicePathInput().getServiceName(),
387 DEVICE_RENDERING_ROLL_BACK_MSG);
388 //FIXME we can't do rollback here, because we don't have rendering results.
389 return renderingResults;
392 rollbackProcessor.addTask(
393 new DeviceRenderingRollbackTask(
395 ! renderingResults.get(0).isSuccess(),
396 renderingResults.get(0).getRenderedNodeInterfaces(),
397 this.deviceRenderer));
398 rollbackProcessor.addTask(
399 new DeviceRenderingRollbackTask("ZtoADeviceTask",
400 ! renderingResults.get(1).isSuccess(),
401 renderingResults.get(1).getRenderedNodeInterfaces(),
402 this.deviceRenderer));
403 return renderingResults;
406 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
407 value = "UPM_UNCALLED_PRIVATE_METHOD",
408 justification = "call in call() method")
409 private List<OtnDeviceRenderingResult> otnDeviceRendering(
410 RollbackProcessor rollbackProcessor,
411 OtnServicePathInput otnServicePathAtoZ,
412 OtnServicePathInput otnServicePathZtoA,
413 String serviceType) {
415 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
416 // Do notifications & LOG.info deserve this ?
417 LOG.info(RENDERING_DEVICES_A_Z_MSG);
419 ServicePathNotificationTypes.ServiceImplementationRequest,
420 otnServicePathAtoZ.getServiceName(),
422 RENDERING_DEVICES_A_Z_MSG);
423 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
424 this.executor.submit(
425 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
427 LOG.info(RENDERING_DEVICES_Z_A_MSG);
429 ServicePathNotificationTypes.ServiceImplementationRequest,
430 otnServicePathZtoA.getServiceName(),
432 RENDERING_DEVICES_Z_A_MSG);
433 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
434 this.executor.submit(
435 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
437 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
438 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
439 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
441 LOG.info("Waiting for A-Z and Z-A device renderers ...");
442 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
443 } catch (InterruptedException | ExecutionException | TimeoutException e) {
444 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
446 ServicePathNotificationTypes.ServiceImplementationRequest,
447 otnServicePathAtoZ.getServiceName(),
449 DEVICE_RENDERING_ROLL_BACK_MSG);
450 //FIXME we can't do rollback here, because we don't have rendering results.
451 return otnRenderingResults;
453 for (int i = 0; i < otnRenderingResults.size(); i++) {
454 rollbackProcessor.addTask(
455 new DeviceRenderingRollbackTask(
456 "DeviceTask n° " + i + 1,
457 ! otnRenderingResults.get(i).isSuccess(),
458 otnRenderingResults.get(i).getRenderedNodeInterfaces(),
459 this.deviceRenderer));
461 return otnRenderingResults;
464 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
465 value = "UPM_UNCALLED_PRIVATE_METHOD",
466 justification = "call in call() method")
467 private void olmPowerSetup(
468 RollbackProcessor rollbackProcessor,
469 ServicePowerSetupInput powerSetupInputAtoZ,
470 ServicePowerSetupInput powerSetupInputZtoA) {
472 //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
473 // Do notifications & LOG.info deserve this ?
474 //TODO use constants for LOG.info & notifications common messages
475 LOG.info("Olm power setup A-Z");
477 ServicePathNotificationTypes.ServiceImplementationRequest,
478 powerSetupInputAtoZ.getServiceName(),
480 "Olm power setup A-Z");
481 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
482 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
484 LOG.info("OLM power setup Z-A");
486 ServicePathNotificationTypes.ServiceImplementationRequest,
487 powerSetupInputAtoZ.getServiceName(),
489 "Olm power setup Z-A");
490 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
491 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
493 ListenableFuture<List<OLMRenderingResult>> olmFutures =
494 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
496 List<OLMRenderingResult> olmResults;
498 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
499 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
500 } catch (InterruptedException | ExecutionException | TimeoutException e) {
501 LOG.warn(OLM_ROLL_BACK_MSG, e);
503 ServicePathNotificationTypes.ServiceImplementationRequest,
504 powerSetupInputAtoZ.getServiceName(),
507 rollbackProcessor.addTask(
508 new OlmPowerSetupRollbackTask("AtoZOLMTask", true, this.olmService, powerSetupInputAtoZ));
509 rollbackProcessor.addTask(
510 new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, this.olmService, powerSetupInputZtoA));
514 rollbackProcessor.addTask(
515 new OlmPowerSetupRollbackTask(
517 ! olmResults.get(0).isSuccess(),
519 powerSetupInputAtoZ));
520 rollbackProcessor.addTask(
521 new OlmPowerSetupRollbackTask(
523 ! olmResults.get(1).isSuccess(),
525 powerSetupInputZtoA));
528 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
529 value = "UPM_UNCALLED_PRIVATE_METHOD",
530 justification = "call in call() method")
531 private boolean isServiceActivated(String nodeId, String tpId) {
532 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
533 for (int i = 0; i < 3; i++) {
534 List<Measurements> measurements = getMeasurements(nodeId, tpId);
535 if (measurements == null) {
536 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
539 if (verifyPreFecBer(measurements)) {
543 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
544 } catch (InterruptedException ex) {
545 Thread.currentThread().interrupt();
548 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
552 private List<Measurements> getMeasurements(String nodeId, String tp) {
554 GetPmOutput getPmOutput =
557 new GetPmInputBuilder()
559 .setGranularity(PmGranularity._15min)
560 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
561 .setResourceType(ResourceTypeEnum.Interface)
565 if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
566 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
568 LOG.info("successfully finished calling OLM's get PM");
569 return getPmOutput.getMeasurements();
573 } catch (ExecutionException | InterruptedException e) {
574 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
579 private boolean verifyPreFecBer(List<Measurements> measurements) {
580 double preFecCorrectedErrors = Double.MIN_VALUE;
581 double fecUncorrectableBlocks = Double.MIN_VALUE;
583 for (Measurements measurement : measurements) {
584 switch (measurement.getPmparameterName()) {
585 case "preFECCorrectedErrors":
586 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
588 case "FECUncorrectableBlocks":
589 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
596 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
597 preFecCorrectedErrors, fecUncorrectableBlocks);
599 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
600 LOG.error("Data has uncorrectable errors, BER test failed");
604 double numOfBitsPerSecond = 112000000000d;
605 double threshold = 0.00002d;
606 double result = preFecCorrectedErrors / numOfBitsPerSecond;
607 LOG.info("PreFEC value is {}", Double.toString(result));
608 return result <= threshold;
611 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
612 value = "UPM_UNCALLED_PRIVATE_METHOD",
613 justification = "call in call() method")
614 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
615 ServicePathInputData servicePathInputDataAtoZ =
617 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
618 ServicePathInputData servicePathInputDataZtoA =
620 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
621 // Rollback should be same for all conditions, so creating a new one
622 RollbackProcessor rollbackProcessor = new RollbackProcessor();
623 List<DeviceRenderingResult> renderingResults =
624 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
625 if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
627 ServicePathNotificationTypes.ServiceImplementationRequest,
628 input.getServiceName(),
630 DEVICE_RENDERING_ROLL_BACK_MSG);
635 //olmPowerSetupInputAtoZ,
636 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
637 //olmPowerSetupInputZtoA
638 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input));
639 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
641 ServicePathNotificationTypes.ServiceImplementationRequest,
642 input.getServiceName(),
647 // run service activation test twice - once on source node and once on
649 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
650 if ((nodes == null) || (nodes.isEmpty())) {
654 Nodes sourceNode = nodes.get(0);
655 Nodes destNode = nodes.get(nodes.size() - 1);
656 String srcNetworkTp =
657 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
658 ? sourceNode.getDestTp()
659 : sourceNode.getSrcTp();
660 String dstNetowrkTp =
661 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
662 ? destNode.getDestTp()
663 : destNode.getSrcTp();
665 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
666 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
667 rollbackProcessor.rollbackAll();
669 ServicePathNotificationTypes.ServiceImplementationRequest,
670 input.getServiceName(),
672 "Service activation test failed.");
675 sendNotificationsWithPathDescription(
676 ServicePathNotificationTypes.ServiceImplementationRequest,
677 input.getServiceName(),
678 RpcStatusEx.Successful,
679 OPERATION_SUCCESSFUL,
680 input.getPathDescription(),
682 renderingResults.stream()
683 .flatMap(rr -> rr.getOtnLinkTps().stream())
684 .collect(Collectors.toList())),
690 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
691 value = "UPM_UNCALLED_PRIVATE_METHOD",
692 justification = "call in call() method")
693 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
694 throws InterruptedException {
695 ServicePathInputData servicePathInputDataAtoZ =
696 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
697 ServicePathInputData servicePathInputDataZtoA =
698 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
699 // OLM turn down power
701 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
703 ServicePathNotificationTypes.ServiceDelete,
706 TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
707 // TODO add some flag rather than string
709 olmPowerTurndown(servicePathInputDataAtoZ)
711 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
713 ServicePathNotificationTypes.ServiceDelete,
716 "Service power turndown failed on A-to-Z path for service");
719 LOG.debug("Turning down power on Z-to-A path");
721 ServicePathNotificationTypes.ServiceDelete,
724 "Turning down power on Z-to-A path");
725 // TODO add some flag rather than string
727 olmPowerTurndown(servicePathInputDataZtoA)
729 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
731 ServicePathNotificationTypes.ServiceDelete,
734 "Service power turndown failed on Z-to-A path for service");
737 } catch (InterruptedException | ExecutionException | TimeoutException e) {
738 LOG.error("Error while turning down power!", e);
741 // delete service path with renderer
742 LOG.info("Deleting service path via renderer");
744 ServicePathNotificationTypes.ServiceDelete,
747 "Deleting service path via renderer");
748 sendNotificationsWithPathDescription(
749 ServicePathNotificationTypes.ServiceDelete,
751 RpcStatusEx.Successful,
752 OPERATION_SUCCESSFUL,
756 new RollbackProcessor(),
757 servicePathInputDataAtoZ,
758 servicePathInputDataZtoA)
760 .flatMap(rr -> rr.getOtnLinkTps().stream())
761 .collect(Collectors.toList())),
767 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
768 value = "UPM_UNCALLED_PRIVATE_METHOD",
769 justification = "call in call() method")
770 private boolean manageOtnServicePathCreation(
771 ServiceImplementationRequestInput input,
773 Uint32 serviceRate) {
774 // Rollback should be same for all conditions, so creating a new one
775 RollbackProcessor rollbackProcessor = new RollbackProcessor();
776 List<OtnDeviceRenderingResult> renderingResults =
781 .rendererCreateOtnServiceInput(
782 input.getServiceName(),
784 input.getServiceAEnd().getServiceFormat().getName(),
786 input.getPathDescription(),
790 .rendererCreateOtnServiceInput(
791 input.getServiceName(),
793 input.getServiceZEnd().getServiceFormat().getName(),
795 input.getPathDescription(),
798 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
799 rollbackProcessor.rollbackAll();
801 ServicePathNotificationTypes.ServiceImplementationRequest,
802 input.getServiceName(),
804 DEVICE_RENDERING_ROLL_BACK_MSG);
807 sendNotificationsWithPathDescription(
808 ServicePathNotificationTypes.ServiceImplementationRequest,
809 input.getServiceName(),
810 RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
811 input.getPathDescription(),
813 renderingResults.stream()
814 .flatMap(rr -> rr.getOtnLinkTps().stream())
815 .collect(Collectors.toList())),
817 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
823 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
824 value = "UPM_UNCALLED_PRIVATE_METHOD",
825 justification = "call in call() method")
826 private boolean manageOtnServicePathDeletion(
828 PathDescription pathDescription,
830 String serviceType) {
831 LOG.info("Deleting otn-service path {} via renderer", serviceName);
833 ServicePathNotificationTypes.ServiceDelete,
836 "Deleting otn-service path via renderer");
837 List<OtnDeviceRenderingResult> renderingResults =
839 new RollbackProcessor(),
842 .rendererCreateOtnServiceInput(
845 service.getServiceAEnd().getServiceFormat().getName(),
846 service.getServiceAEnd().getServiceRate(),
851 .rendererCreateOtnServiceInput(
854 service.getServiceZEnd().getServiceFormat().getName(),
855 service.getServiceAEnd().getServiceRate(),
859 sendNotificationsWithPathDescription(
860 ServicePathNotificationTypes.ServiceDelete,
862 RpcStatusEx.Successful,
863 OPERATION_SUCCESSFUL,
866 renderingResults.stream()
867 .flatMap(rr -> rr.getOtnLinkTps().stream())
868 .collect(Collectors.toList())),
870 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
877 * Send renderer notification.
878 * @param servicePathNotificationTypes ServicePathNotificationTypes
879 * @param serviceName String
880 * @param rpcStatusEx RpcStatusEx
881 * @param message String
883 private void sendNotifications(
884 ServicePathNotificationTypes servicePathNotificationTypes,
886 RpcStatusEx rpcStatusEx,
889 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
890 null, null, null, null));
894 * Send renderer notification with path description information.
895 * @param servicePathNotificationTypes ServicePathNotificationTypes
896 * @param serviceName String
897 * @param rpcStatusEx RpcStatusEx
898 * @param message String
899 * @param pathDescription PathDescription
901 private void sendNotificationsWithPathDescription(
902 ServicePathNotificationTypes servicePathNotificationTypes,
904 RpcStatusEx rpcStatusEx,
906 PathDescription pathDescription,
908 List<String> supportedLinks,
909 String serviceType) {
911 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
912 pathDescription, notifLink, supportedLinks, serviceType));
916 * Build notification containing path description information.
917 * @param servicePathNotificationTypes ServicePathNotificationTypes
918 * @param serviceName String
919 * @param rpcStatusEx RpcStatusEx
920 * @param message String
921 * @param pathDescription PathDescription
922 * @return notification with RendererRpcResultSp type.
924 private RendererRpcResultSp buildNotification(
925 ServicePathNotificationTypes servicePathNotificationTypes,
927 RpcStatusEx rpcStatusEx,
929 PathDescription pathDescription,
931 List<String> supportedLinks,
932 String serviceType) {
933 RendererRpcResultSpBuilder builder =
934 new RendererRpcResultSpBuilder()
935 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
936 .setStatusMessage(message)
937 .setServiceType(serviceType);
938 if (pathDescription != null) {
940 .setAToZDirection(pathDescription.getAToZDirection())
941 .setZToADirection(pathDescription.getZToADirection());
943 if (notifLink != null) {
944 builder.setLink(notifLink);
946 if (supportedLinks != null) {
947 builder.setLinkId(supportedLinks);
949 return builder.build();
953 * Send renderer notification.
954 * @param notification Notification
956 private void send(Notification notification) {
958 LOG.info("Sending notification {}", notification);
959 notificationPublishService.putNotification(notification);
960 } catch (InterruptedException e) {
961 LOG.info("notification offer rejected: ", e);
962 Thread.currentThread().interrupt();
966 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
968 otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
972 new ATerminationBuilder()
973 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
974 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
977 new ZTerminationBuilder()
978 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
979 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
984 private List<String> getSupportedLinks(List<String> allSupportLinks, String serviceType) {
985 //TODO a Map might be more indicated here
986 switch (serviceType) {
987 case StringConstants.SERVICE_TYPE_10GE:
988 case StringConstants.SERVICE_TYPE_1GE:
989 return allSupportLinks.stream()
990 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toList());
991 case StringConstants.SERVICE_TYPE_100GE_M:
992 return allSupportLinks.stream()
993 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toList());
994 case StringConstants.SERVICE_TYPE_ODU4:
995 case StringConstants.SERVICE_TYPE_100GE_S:
996 return allSupportLinks.stream()
997 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
998 case StringConstants.SERVICE_TYPE_ODUC4:
999 return allSupportLinks.stream()
1000 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());