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;
19 import java.util.concurrent.Callable;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Executors;
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.common.api.LogicalDatastoreType;
28 import org.opendaylight.transportpce.common.ResponseCodes;
29 import org.opendaylight.transportpce.common.StringConstants;
30 import org.opendaylight.transportpce.common.Timeouts;
31 import org.opendaylight.transportpce.common.mapping.PortMapping;
32 import org.opendaylight.transportpce.common.service.ServiceTypes;
33 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
34 import org.opendaylight.transportpce.renderer.ServicePathInputData;
35 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
36 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630.OtnLinkType;
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.resource.types.rev161014.ResourceTypeEnum;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.PathDescription;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.PmGranularity;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.link.tp.LinkTp;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.olm.get.pm.input.ResourceIdentifierBuilder;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.optical.renderer.nodes.Nodes;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.opendaylight.yangtools.yang.binding.Notification;
78 import org.opendaylight.yangtools.yang.common.Uint32;
79 import org.osgi.service.component.annotations.Activate;
80 import org.osgi.service.component.annotations.Component;
81 import org.osgi.service.component.annotations.Reference;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 @Component(immediate = true)
87 public class RendererServiceOperationsImpl implements RendererServiceOperations {
89 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
90 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
91 "Device rendering was not successful! Rendering will be rolled back.";
92 private static final String OLM_ROLL_BACK_MSG =
93 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
94 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
95 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
96 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
97 private static final String FAILED = "Failed";
98 private static final String OPERATION_FAILED = "Operation Failed";
99 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
100 private static final int NUMBER_OF_THREADS = 4;
102 private final DeviceRendererService deviceRenderer;
103 private final OtnDeviceRendererService otnDeviceRenderer;
104 private final TransportpceOlmService olmService;
105 private final DataBroker dataBroker;
106 private final NotificationPublishService notificationPublishService;
107 private final PortMapping portMapping;
108 private ListeningExecutorService executor;
111 public RendererServiceOperationsImpl(@Reference DeviceRendererService deviceRenderer,
112 @Reference OtnDeviceRendererService otnDeviceRenderer,
113 @Reference TransportpceOlmService olmService,
114 @Reference DataBroker dataBroker,
115 @Reference NotificationPublishService notificationPublishService,
116 @Reference PortMapping portMapping) {
117 this.deviceRenderer = deviceRenderer;
118 this.otnDeviceRenderer = otnDeviceRenderer;
119 this.olmService = olmService;
120 this.dataBroker = dataBroker;
121 this.notificationPublishService = notificationPublishService;
122 this.portMapping = portMapping;
123 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
124 LOG.debug("RendererServiceOperationsImpl instantiated");
128 public ListenableFuture<ServiceImplementationRequestOutput>
129 serviceImplementation(ServiceImplementationRequestInput input, boolean isTempService) {
130 LOG.info("Calling service impl request {}", input.getServiceName());
131 LOG.debug("Check if it is temp-service {}", isTempService);
132 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
135 public ServiceImplementationRequestOutput call() throws Exception {
137 ServicePathNotificationTypes.ServiceImplementationRequest,
138 input.getServiceName(),
140 "Service compliant, submitting service implementation Request ...");
141 Uint32 serviceRate = getServiceRate(input);
142 LOG.info("Using {}G rate", serviceRate);
143 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220922
144 .network.Nodes mappingNode =
145 portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
146 ? portMapping.getNode(input.getServiceAEnd().getNodeId())
148 String serviceType = ServiceTypes.getServiceType(
149 input.getServiceAEnd().getServiceFormat().getName(),
152 && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
153 && input.getServiceAEnd().getTxDirection() != null
154 && input.getServiceAEnd().getTxDirection().getPort() != null
155 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
156 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
157 input.getServiceAEnd().getTxDirection().getPort().getPortName())
159 //TODO a Map might be more indicated here
160 switch (serviceType) {
161 case StringConstants.SERVICE_TYPE_100GE_T:
162 case StringConstants.SERVICE_TYPE_400GE:
163 case StringConstants.SERVICE_TYPE_OTU4:
164 case StringConstants.SERVICE_TYPE_OTUC2:
165 case StringConstants.SERVICE_TYPE_OTUC3:
166 case StringConstants.SERVICE_TYPE_OTUC4:
167 LOG.debug("Check temp service {}", isTempService);
168 if (!manageServicePathCreation(input, serviceType, isTempService)) {
169 return ModelMappingUtils
170 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
173 case StringConstants.SERVICE_TYPE_1GE:
174 case StringConstants.SERVICE_TYPE_10GE:
175 case StringConstants.SERVICE_TYPE_100GE_M:
176 case StringConstants.SERVICE_TYPE_100GE_S:
177 case StringConstants.SERVICE_TYPE_ODU4:
178 case StringConstants.SERVICE_TYPE_ODUC2:
179 case StringConstants.SERVICE_TYPE_ODUC3:
180 case StringConstants.SERVICE_TYPE_ODUC4:
181 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
182 return ModelMappingUtils
183 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
187 LOG.error("unsupported service-type");
188 return ModelMappingUtils
189 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
191 return ModelMappingUtils
192 .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
198 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
199 String serviceName = input.getServiceName();
200 LOG.info("Calling service delete request {}", serviceName);
201 return executor.submit(new Callable<ServiceDeleteOutput>() {
204 public ServiceDeleteOutput call() throws Exception {
206 ServicePathNotificationTypes.ServiceDelete,
209 "Service compliant, submitting service delete Request ...");
210 // Obtain path description
212 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
213 .service.path.PathDescription> pathDescriptionOpt =
214 getPathDescriptionFromDatastore(serviceName);
215 if (pathDescriptionOpt.isEmpty()) {
216 LOG.error("Unable to get path description for service {}!", serviceName);
218 ServicePathNotificationTypes.ServiceDelete,
221 "Unable to get path description for service");
222 return ModelMappingUtils
223 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
225 PathDescription pathDescription = pathDescriptionOpt.orElseThrow();
227 ServiceTypes.getServiceType(
228 service.getServiceAEnd().getServiceFormat().getName(),
229 service.getServiceAEnd().getServiceRate(),
230 service.getServiceAEnd().getTxDirection() == null
231 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
233 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
234 .getPort().getPortName() == null
236 : portMapping.getMapping(
237 service.getServiceAEnd().getNodeId().getValue(),
238 service.getServiceAEnd().getTxDirection().values().stream().findFirst()
239 .orElseThrow().getPort().getPortName()));
240 switch (serviceType) {
241 case StringConstants.SERVICE_TYPE_100GE_T:
242 case StringConstants.SERVICE_TYPE_400GE:
243 case StringConstants.SERVICE_TYPE_OTU4:
244 case StringConstants.SERVICE_TYPE_OTUC2:
245 case StringConstants.SERVICE_TYPE_OTUC3:
246 case StringConstants.SERVICE_TYPE_OTUC4:
247 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
248 return ModelMappingUtils
249 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
252 case StringConstants.SERVICE_TYPE_1GE:
253 case StringConstants.SERVICE_TYPE_10GE:
254 case StringConstants.SERVICE_TYPE_100GE_M:
255 case StringConstants.SERVICE_TYPE_100GE_S:
256 case StringConstants.SERVICE_TYPE_ODU4:
257 case StringConstants.SERVICE_TYPE_ODUC2:
258 case StringConstants.SERVICE_TYPE_ODUC3:
259 case StringConstants.SERVICE_TYPE_ODUC4:
260 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
261 return ModelMappingUtils
262 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
266 LOG.error("unsupported service-type");
267 return ModelMappingUtils
268 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
270 return ModelMappingUtils
271 .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
276 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
277 value = "UPM_UNCALLED_PRIVATE_METHOD",
278 justification = "call in call() method")
279 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
280 if (input.getServiceAEnd() == null) {
281 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
284 if (input.getServiceAEnd().getServiceRate() != null) {
285 return input.getServiceAEnd().getServiceRate();
287 LOG.warn("Input should have rate if you are using 200 or 300G");
288 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
289 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
290 ServiceFormat.OTU, Map.of(
291 "OTUCn", Uint32.valueOf(400),
292 "OTU4", Uint32.valueOf(100),
293 "OTU2", Uint32.valueOf(10),
294 "OTU2e", Uint32.valueOf(10)),
295 ServiceFormat.ODU, Map.of(
296 "ODUCn",Uint32.valueOf(400),
297 "ODU4", Uint32.valueOf(100),
298 "ODU2", Uint32.valueOf(10),
299 "ODU2e", Uint32.valueOf(10),
300 "ODU0", Uint32.valueOf(1)));
301 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
302 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
303 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
307 ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
308 ? input.getServiceAEnd().getOtuServiceRate().toString().split("\\{")[0]
309 : input.getServiceAEnd().getOduServiceRate().toString().split("\\{")[0];
310 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
311 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
312 input.getServiceName(), serviceName);
316 .get(input.getServiceAEnd().getServiceFormat())
320 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
321 value = "UPM_UNCALLED_PRIVATE_METHOD",
322 justification = "call in call() method")
323 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
324 throws InterruptedException, ExecutionException, TimeoutException {
325 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
326 return this.olmService
327 .servicePowerTurndown(
328 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build())
329 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS)
333 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
334 value = "UPM_UNCALLED_PRIVATE_METHOD",
335 justification = "call in call() method")
336 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
337 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
338 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
339 .service.path.PathDescription> pathDescriptionIID =
340 InstanceIdentifier.create(ServicePathList.class)
341 .child(ServicePaths.class, new ServicePathsKey(serviceName))
342 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
343 .service.path.PathDescription.class);
345 LOG.debug("Getting path description for service {}", serviceName);
346 return this.dataBroker.newReadOnlyTransaction()
347 .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
348 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
349 } catch (InterruptedException | ExecutionException | TimeoutException e) {
350 LOG.warn("Exception while getting path description from datastore {} for service {}!",
351 pathDescriptionIID, serviceName, e);
352 return Optional.empty();
356 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
357 value = "UPM_UNCALLED_PRIVATE_METHOD",
358 justification = "call in call() method")
359 private List<DeviceRenderingResult> deviceRendering(
360 RollbackProcessor rollbackProcessor,
361 ServicePathInputData servicePathDataAtoZ,
362 ServicePathInputData servicePathDataZtoA) {
364 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
365 // Do notifications & LOG.info deserve this ?
366 LOG.info(RENDERING_DEVICES_A_Z_MSG);
368 ServicePathNotificationTypes.ServiceImplementationRequest,
369 servicePathDataAtoZ.getServicePathInput().getServiceName(),
371 RENDERING_DEVICES_A_Z_MSG);
372 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
373 this.executor.submit(
374 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z));
376 LOG.info(RENDERING_DEVICES_Z_A_MSG);
378 ServicePathNotificationTypes.ServiceImplementationRequest,
379 servicePathDataZtoA.getServicePathInput().getServiceName(),
381 RENDERING_DEVICES_Z_A_MSG);
382 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
383 this.executor.submit(
384 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A));
386 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
387 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
389 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
391 LOG.info("Waiting for A-Z and Z-A device renderers ...");
392 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
393 } catch (InterruptedException | ExecutionException | TimeoutException e) {
394 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
396 ServicePathNotificationTypes.ServiceImplementationRequest,
397 servicePathDataAtoZ.getServicePathInput().getServiceName(),
399 DEVICE_RENDERING_ROLL_BACK_MSG);
400 //FIXME we can't do rollback here, because we don't have rendering results.
401 return renderingResults;
404 rollbackProcessor.addTask(
405 new DeviceRenderingRollbackTask(
407 ! renderingResults.get(0).isSuccess(),
408 renderingResults.get(0).getRenderedNodeInterfaces(),
409 this.deviceRenderer));
410 rollbackProcessor.addTask(
411 new DeviceRenderingRollbackTask("ZtoADeviceTask",
412 ! renderingResults.get(1).isSuccess(),
413 renderingResults.get(1).getRenderedNodeInterfaces(),
414 this.deviceRenderer));
415 return renderingResults;
418 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
419 value = "UPM_UNCALLED_PRIVATE_METHOD",
420 justification = "call in call() method")
421 private List<OtnDeviceRenderingResult> otnDeviceRendering(
422 RollbackProcessor rollbackProcessor,
423 OtnServicePathInput otnServicePathAtoZ,
424 OtnServicePathInput otnServicePathZtoA,
425 String serviceType) {
427 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
428 // Do notifications & LOG.info deserve this ?
429 LOG.info(RENDERING_DEVICES_A_Z_MSG);
431 ServicePathNotificationTypes.ServiceImplementationRequest,
432 otnServicePathAtoZ.getServiceName(),
434 RENDERING_DEVICES_A_Z_MSG);
435 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
436 this.executor.submit(
437 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
439 LOG.info(RENDERING_DEVICES_Z_A_MSG);
441 ServicePathNotificationTypes.ServiceImplementationRequest,
442 otnServicePathZtoA.getServiceName(),
444 RENDERING_DEVICES_Z_A_MSG);
445 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
446 this.executor.submit(
447 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
449 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
450 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
451 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
453 LOG.info("Waiting for A-Z and Z-A device renderers ...");
454 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
455 } catch (InterruptedException | ExecutionException | TimeoutException e) {
456 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
458 ServicePathNotificationTypes.ServiceImplementationRequest,
459 otnServicePathAtoZ.getServiceName(),
461 DEVICE_RENDERING_ROLL_BACK_MSG);
462 //FIXME we can't do rollback here, because we don't have rendering results.
463 return otnRenderingResults;
465 for (int i = 0; i < otnRenderingResults.size(); i++) {
466 rollbackProcessor.addTask(
467 new DeviceRenderingRollbackTask(
468 "DeviceTask n° " + i + 1,
469 ! otnRenderingResults.get(i).isSuccess(),
470 otnRenderingResults.get(i).getRenderedNodeInterfaces(),
471 this.deviceRenderer));
473 return otnRenderingResults;
476 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
477 value = "UPM_UNCALLED_PRIVATE_METHOD",
478 justification = "call in call() method")
479 private void olmPowerSetup(
480 RollbackProcessor rollbackProcessor,
481 ServicePowerSetupInput powerSetupInputAtoZ,
482 ServicePowerSetupInput powerSetupInputZtoA, boolean isTempService) {
484 //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
485 // Do notifications & LOG.info deserve this ?
486 //TODO use constants for LOG.info & notifications common messages
487 // if the service create is a temp-service, OLM will be skipped
489 LOG.info("For temp-service create OLM is not computed and skipped");
492 LOG.info("Olm power setup A-Z");
494 ServicePathNotificationTypes.ServiceImplementationRequest,
495 powerSetupInputAtoZ.getServiceName(),
497 "Olm power setup A-Z");
498 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
499 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
501 LOG.info("OLM power setup Z-A");
503 ServicePathNotificationTypes.ServiceImplementationRequest,
504 powerSetupInputAtoZ.getServiceName(),
506 "Olm power setup Z-A");
507 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
508 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
509 ListenableFuture<List<OLMRenderingResult>> olmFutures =
510 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
512 List<OLMRenderingResult> olmResults;
514 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
515 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
516 } catch (InterruptedException | ExecutionException | TimeoutException e) {
517 LOG.warn(OLM_ROLL_BACK_MSG, e);
519 ServicePathNotificationTypes.ServiceImplementationRequest,
520 powerSetupInputAtoZ.getServiceName(),
523 rollbackProcessor.addTask(
524 new OlmPowerSetupRollbackTask("AtoZOLMTask", true, this.olmService, powerSetupInputAtoZ));
525 rollbackProcessor.addTask(
526 new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, this.olmService, powerSetupInputZtoA));
529 rollbackProcessor.addTask(
530 new OlmPowerSetupRollbackTask(
532 !olmResults.get(0).isSuccess(),
534 powerSetupInputAtoZ));
535 rollbackProcessor.addTask(
536 new OlmPowerSetupRollbackTask(
538 !olmResults.get(1).isSuccess(),
540 powerSetupInputZtoA));
543 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
544 value = "UPM_UNCALLED_PRIVATE_METHOD",
545 justification = "call in call() method")
546 private boolean isServiceActivated(String nodeId, String tpId) {
547 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
548 for (int i = 0; i < 3; i++) {
549 List<Measurements> measurements = getMeasurements(nodeId, tpId);
550 if (measurements == null) {
551 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
554 if (verifyPreFecBer(measurements)) {
558 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
559 } catch (InterruptedException ex) {
560 Thread.currentThread().interrupt();
563 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
567 private List<Measurements> getMeasurements(String nodeId, String tp) {
569 GetPmOutput getPmOutput =
572 new GetPmInputBuilder()
574 .setGranularity(PmGranularity._15min)
575 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
576 .setResourceType(ResourceTypeEnum.Interface)
580 if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
581 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
583 LOG.info("successfully finished calling OLM's get PM");
584 return getPmOutput.getMeasurements();
588 } catch (ExecutionException | InterruptedException e) {
589 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
594 private boolean verifyPreFecBer(List<Measurements> measurements) {
595 double preFecCorrectedErrors = Double.MIN_VALUE;
596 double fecUncorrectableBlocks = Double.MIN_VALUE;
598 for (Measurements measurement : measurements) {
599 switch (measurement.getPmparameterName()) {
600 case "preFECCorrectedErrors":
601 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
603 case "FECUncorrectableBlocks":
604 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
611 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
612 preFecCorrectedErrors, fecUncorrectableBlocks);
614 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
615 LOG.error("Data has uncorrectable errors, BER test failed");
619 double numOfBitsPerSecond = 112000000000d;
620 double threshold = 0.00002d;
621 double result = preFecCorrectedErrors / numOfBitsPerSecond;
622 LOG.info("PreFEC value is {}", Double.toString(result));
623 return result <= threshold;
626 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
627 value = "UPM_UNCALLED_PRIVATE_METHOD",
628 justification = "call in call() method")
629 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
630 boolean isTempService) {
631 ServicePathInputData servicePathInputDataAtoZ =
633 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
634 ServicePathInputData servicePathInputDataZtoA =
636 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
637 // Rollback should be same for all conditions, so creating a new one
638 RollbackProcessor rollbackProcessor = new RollbackProcessor();
639 List<DeviceRenderingResult> renderingResults =
640 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
641 if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
643 ServicePathNotificationTypes.ServiceImplementationRequest,
644 input.getServiceName(),
646 DEVICE_RENDERING_ROLL_BACK_MSG);
651 //olmPowerSetupInputAtoZ,
652 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
653 //olmPowerSetupInputZtoA
654 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input), isTempService);
655 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
657 ServicePathNotificationTypes.ServiceImplementationRequest,
658 input.getServiceName(),
663 // run service activation test twice - once on source node and once on
665 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
666 if ((nodes == null) || (nodes.isEmpty())) {
670 Nodes sourceNode = nodes.get(0);
671 Nodes destNode = nodes.get(nodes.size() - 1);
672 String srcNetworkTp =
673 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
674 ? sourceNode.getDestTp()
675 : sourceNode.getSrcTp();
676 String dstNetowrkTp =
677 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
678 ? destNode.getDestTp()
679 : destNode.getSrcTp();
681 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
682 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
683 rollbackProcessor.rollbackAll();
685 ServicePathNotificationTypes.ServiceImplementationRequest,
686 input.getServiceName(),
688 "Service activation test failed.");
691 sendNotificationsWithPathDescription(
692 ServicePathNotificationTypes.ServiceImplementationRequest,
693 input.getServiceName(),
694 RpcStatusEx.Successful,
695 OPERATION_SUCCESSFUL,
696 input.getPathDescription(),
698 renderingResults.stream()
699 .flatMap(rr -> rr.getOtnLinkTps().stream())
700 .collect(Collectors.toList())),
706 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
707 value = "UPM_UNCALLED_PRIVATE_METHOD",
708 justification = "call in call() method")
709 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
710 throws InterruptedException {
711 ServicePathInputData servicePathInputDataAtoZ =
712 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
713 ServicePathInputData servicePathInputDataZtoA =
714 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
715 // OLM turn down power
717 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
719 ServicePathNotificationTypes.ServiceDelete,
722 TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
723 // TODO add some flag rather than string
725 olmPowerTurndown(servicePathInputDataAtoZ)
727 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
729 ServicePathNotificationTypes.ServiceDelete,
732 "Service power turndown failed on A-to-Z path for service");
735 LOG.debug("Turning down power on Z-to-A path");
737 ServicePathNotificationTypes.ServiceDelete,
740 "Turning down power on Z-to-A path");
741 // TODO add some flag rather than string
743 olmPowerTurndown(servicePathInputDataZtoA)
745 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
747 ServicePathNotificationTypes.ServiceDelete,
750 "Service power turndown failed on Z-to-A path for service");
753 } catch (InterruptedException | ExecutionException | TimeoutException e) {
754 LOG.error("Error while turning down power!", e);
757 // delete service path with renderer
758 LOG.info("Deleting service path via renderer");
760 ServicePathNotificationTypes.ServiceDelete,
763 "Deleting service path via renderer");
764 sendNotificationsWithPathDescription(
765 ServicePathNotificationTypes.ServiceDelete,
767 RpcStatusEx.Successful,
768 OPERATION_SUCCESSFUL,
772 new RollbackProcessor(),
773 servicePathInputDataAtoZ,
774 servicePathInputDataZtoA)
776 .flatMap(rr -> rr.getOtnLinkTps().stream())
777 .collect(Collectors.toList())),
783 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
784 value = "UPM_UNCALLED_PRIVATE_METHOD",
785 justification = "call in call() method")
786 private boolean manageOtnServicePathCreation(
787 ServiceImplementationRequestInput input,
789 Uint32 serviceRate) {
790 // Rollback should be same for all conditions, so creating a new one
791 RollbackProcessor rollbackProcessor = new RollbackProcessor();
792 List<OtnDeviceRenderingResult> renderingResults =
797 .rendererCreateOtnServiceInput(
798 input.getServiceName(),
800 input.getServiceAEnd().getServiceFormat().getName(),
802 input.getPathDescription(),
806 .rendererCreateOtnServiceInput(
807 input.getServiceName(),
809 input.getServiceZEnd().getServiceFormat().getName(),
811 input.getPathDescription(),
814 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
815 rollbackProcessor.rollbackAll();
817 ServicePathNotificationTypes.ServiceImplementationRequest,
818 input.getServiceName(),
820 DEVICE_RENDERING_ROLL_BACK_MSG);
823 sendNotificationsWithPathDescription(
824 ServicePathNotificationTypes.ServiceImplementationRequest,
825 input.getServiceName(),
826 RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
827 input.getPathDescription(),
829 renderingResults.stream()
830 .flatMap(rr -> rr.getOtnLinkTps().stream())
831 .collect(Collectors.toList())),
833 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
839 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
840 value = "UPM_UNCALLED_PRIVATE_METHOD",
841 justification = "call in call() method")
842 private boolean manageOtnServicePathDeletion(
844 PathDescription pathDescription,
846 String serviceType) {
847 LOG.info("Deleting otn-service path {} via renderer", serviceName);
849 ServicePathNotificationTypes.ServiceDelete,
852 "Deleting otn-service path via renderer");
853 List<OtnDeviceRenderingResult> renderingResults =
855 new RollbackProcessor(),
858 .rendererCreateOtnServiceInput(
861 service.getServiceAEnd().getServiceFormat().getName(),
862 service.getServiceAEnd().getServiceRate(),
867 .rendererCreateOtnServiceInput(
870 service.getServiceZEnd().getServiceFormat().getName(),
871 service.getServiceAEnd().getServiceRate(),
875 sendNotificationsWithPathDescription(
876 ServicePathNotificationTypes.ServiceDelete,
878 RpcStatusEx.Successful,
879 OPERATION_SUCCESSFUL,
882 renderingResults.stream()
883 .flatMap(rr -> rr.getOtnLinkTps().stream())
884 .collect(Collectors.toList())),
886 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
893 * Send renderer notification.
894 * @param servicePathNotificationTypes ServicePathNotificationTypes
895 * @param serviceName String
896 * @param rpcStatusEx RpcStatusEx
897 * @param message String
899 private void sendNotifications(
900 ServicePathNotificationTypes servicePathNotificationTypes,
902 RpcStatusEx rpcStatusEx,
905 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
906 null, null, null, null));
910 * Send renderer notification with path description information.
911 * @param servicePathNotificationTypes ServicePathNotificationTypes
912 * @param serviceName String
913 * @param rpcStatusEx RpcStatusEx
914 * @param message String
915 * @param pathDescription PathDescription
917 private void sendNotificationsWithPathDescription(
918 ServicePathNotificationTypes servicePathNotificationTypes,
920 RpcStatusEx rpcStatusEx,
922 PathDescription pathDescription,
924 Set<String> supportedLinks,
925 String serviceType) {
927 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
928 pathDescription, notifLink, supportedLinks, serviceType));
932 * Build notification containing path description information.
933 * @param servicePathNotificationTypes ServicePathNotificationTypes
934 * @param serviceName String
935 * @param rpcStatusEx RpcStatusEx
936 * @param message String
937 * @param pathDescription PathDescription
938 * @return notification with RendererRpcResultSp type.
940 private RendererRpcResultSp buildNotification(
941 ServicePathNotificationTypes servicePathNotificationTypes,
943 RpcStatusEx rpcStatusEx,
945 PathDescription pathDescription,
947 Set<String> supportedLinks,
948 String serviceType) {
949 RendererRpcResultSpBuilder builder =
950 new RendererRpcResultSpBuilder()
951 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
952 .setStatusMessage(message)
953 .setServiceType(serviceType);
954 if (pathDescription != null) {
956 .setAToZDirection(pathDescription.getAToZDirection())
957 .setZToADirection(pathDescription.getZToADirection());
959 if (notifLink != null) {
960 builder.setLink(notifLink);
962 if (supportedLinks != null) {
963 builder.setLinkId(supportedLinks);
965 return builder.build();
969 * Send renderer notification.
970 * @param notification Notification
972 private void send(Notification<?> notification) {
974 LOG.info("Sending notification {}", notification);
975 notificationPublishService.putNotification(notification);
976 } catch (InterruptedException e) {
977 LOG.info("notification offer rejected: ", e);
978 Thread.currentThread().interrupt();
982 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
984 otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
988 new ATerminationBuilder()
989 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
990 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
993 new ZTerminationBuilder()
994 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
995 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
1000 private Set<String> getSupportedLinks(Set<String> allSupportLinks, String serviceType) {
1001 //TODO a Map might be more indicated here
1002 switch (serviceType) {
1003 case StringConstants.SERVICE_TYPE_10GE:
1004 case StringConstants.SERVICE_TYPE_1GE:
1005 return allSupportLinks.stream()
1006 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toSet());
1007 case StringConstants.SERVICE_TYPE_100GE_M:
1008 return allSupportLinks.stream()
1009 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toSet());
1010 case StringConstants.SERVICE_TYPE_ODU4:
1011 case StringConstants.SERVICE_TYPE_100GE_S:
1012 return allSupportLinks.stream()
1013 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toSet());
1014 case StringConstants.SERVICE_TYPE_ODUC4:
1015 return allSupportLinks.stream()
1016 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toSet());