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.rev210705.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) {
130 LOG.info("Calling service impl request {}", input.getServiceName());
131 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
134 public ServiceImplementationRequestOutput call() throws Exception {
136 ServicePathNotificationTypes.ServiceImplementationRequest,
137 input.getServiceName(),
139 "Service compliant, submitting service implementation Request ...");
140 Uint32 serviceRate = getServiceRate(input);
141 LOG.info("Using {}G rate", serviceRate);
142 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220922
143 .network.Nodes mappingNode =
144 portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
145 ? portMapping.getNode(input.getServiceAEnd().getNodeId())
147 String serviceType = ServiceTypes.getServiceType(
148 input.getServiceAEnd().getServiceFormat().getName(),
151 && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
152 && input.getServiceAEnd().getTxDirection() != null
153 && input.getServiceAEnd().getTxDirection().getPort() != null
154 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
155 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
156 input.getServiceAEnd().getTxDirection().getPort().getPortName())
158 //TODO a Map might be more indicated here
159 switch (serviceType) {
160 case StringConstants.SERVICE_TYPE_100GE_T:
161 case StringConstants.SERVICE_TYPE_400GE:
162 case StringConstants.SERVICE_TYPE_OTU4:
163 case StringConstants.SERVICE_TYPE_OTUC2:
164 case StringConstants.SERVICE_TYPE_OTUC3:
165 case StringConstants.SERVICE_TYPE_OTUC4:
166 if (!manageServicePathCreation(input, serviceType)) {
167 return ModelMappingUtils
168 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
171 case StringConstants.SERVICE_TYPE_1GE:
172 case StringConstants.SERVICE_TYPE_10GE:
173 case StringConstants.SERVICE_TYPE_100GE_M:
174 case StringConstants.SERVICE_TYPE_100GE_S:
175 case StringConstants.SERVICE_TYPE_ODU4:
176 case StringConstants.SERVICE_TYPE_ODUC2:
177 case StringConstants.SERVICE_TYPE_ODUC3:
178 case StringConstants.SERVICE_TYPE_ODUC4:
179 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
180 return ModelMappingUtils
181 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
185 LOG.error("unsupported service-type");
186 return ModelMappingUtils
187 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
189 return ModelMappingUtils
190 .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
196 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
197 String serviceName = input.getServiceName();
198 LOG.info("Calling service delete request {}", serviceName);
199 return executor.submit(new Callable<ServiceDeleteOutput>() {
202 public ServiceDeleteOutput call() throws Exception {
204 ServicePathNotificationTypes.ServiceDelete,
207 "Service compliant, submitting service delete Request ...");
208 // Obtain path description
210 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
211 .service.path.PathDescription> pathDescriptionOpt =
212 getPathDescriptionFromDatastore(serviceName);
213 if (pathDescriptionOpt.isEmpty()) {
214 LOG.error("Unable to get path description for service {}!", serviceName);
216 ServicePathNotificationTypes.ServiceDelete,
219 "Unable to get path description for service");
220 return ModelMappingUtils
221 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
223 PathDescription pathDescription = pathDescriptionOpt.get();
225 ServiceTypes.getServiceType(
226 service.getServiceAEnd().getServiceFormat().getName(),
227 service.getServiceAEnd().getServiceRate(),
228 service.getServiceAEnd().getTxDirection() == null
229 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
231 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
232 .getPort().getPortName() == null
234 : portMapping.getMapping(
235 service.getServiceAEnd().getNodeId().getValue(),
236 service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
237 .getPort().getPortName()));
238 switch (serviceType) {
239 case StringConstants.SERVICE_TYPE_100GE_T:
240 case StringConstants.SERVICE_TYPE_400GE:
241 case StringConstants.SERVICE_TYPE_OTU4:
242 case StringConstants.SERVICE_TYPE_OTUC2:
243 case StringConstants.SERVICE_TYPE_OTUC3:
244 case StringConstants.SERVICE_TYPE_OTUC4:
245 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
246 return ModelMappingUtils
247 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
250 case StringConstants.SERVICE_TYPE_1GE:
251 case StringConstants.SERVICE_TYPE_10GE:
252 case StringConstants.SERVICE_TYPE_100GE_M:
253 case StringConstants.SERVICE_TYPE_100GE_S:
254 case StringConstants.SERVICE_TYPE_ODU4:
255 case StringConstants.SERVICE_TYPE_ODUC2:
256 case StringConstants.SERVICE_TYPE_ODUC3:
257 case StringConstants.SERVICE_TYPE_ODUC4:
258 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
259 return ModelMappingUtils
260 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
264 LOG.error("unsupported service-type");
265 return ModelMappingUtils
266 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
268 return ModelMappingUtils
269 .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
274 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
275 value = "UPM_UNCALLED_PRIVATE_METHOD",
276 justification = "call in call() method")
277 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
278 if (input.getServiceAEnd() == null) {
279 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
282 if (input.getServiceAEnd().getServiceRate() != null) {
283 return input.getServiceAEnd().getServiceRate();
285 LOG.warn("Input should have rate if you are using 200 or 300G");
286 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
287 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
288 ServiceFormat.OTU, Map.of(
289 "OTUCn", Uint32.valueOf(400),
290 "OTU4", Uint32.valueOf(100),
291 "OTU2", Uint32.valueOf(10),
292 "OTU2e", Uint32.valueOf(10)),
293 ServiceFormat.ODU, Map.of(
294 "ODUCn",Uint32.valueOf(400),
295 "ODU4", Uint32.valueOf(100),
296 "ODU2", Uint32.valueOf(10),
297 "ODU2e", Uint32.valueOf(10),
298 "ODU0", Uint32.valueOf(1)));
299 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
300 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
301 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
305 ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
306 ? input.getServiceAEnd().getOtuServiceRate().toString().split("\\{")[0]
307 : input.getServiceAEnd().getOduServiceRate().toString().split("\\{")[0];
308 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
309 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
310 input.getServiceName(), serviceName);
314 .get(input.getServiceAEnd().getServiceFormat())
318 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
319 value = "UPM_UNCALLED_PRIVATE_METHOD",
320 justification = "call in call() method")
321 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
322 throws InterruptedException, ExecutionException, TimeoutException {
323 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
324 return this.olmService
325 .servicePowerTurndown(
326 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build())
327 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS)
331 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
332 value = "UPM_UNCALLED_PRIVATE_METHOD",
333 justification = "call in call() method")
334 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
335 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
336 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
337 .service.path.PathDescription> pathDescriptionIID =
338 InstanceIdentifier.create(ServicePathList.class)
339 .child(ServicePaths.class, new ServicePathsKey(serviceName))
340 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
341 .service.path.PathDescription.class);
343 LOG.debug("Getting path description for service {}", serviceName);
344 return this.dataBroker.newReadOnlyTransaction()
345 .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
346 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
347 } catch (InterruptedException | ExecutionException | TimeoutException e) {
348 LOG.warn("Exception while getting path description from datastore {} for service {}!",
349 pathDescriptionIID, serviceName, e);
350 return Optional.empty();
354 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
355 value = "UPM_UNCALLED_PRIVATE_METHOD",
356 justification = "call in call() method")
357 private List<DeviceRenderingResult> deviceRendering(
358 RollbackProcessor rollbackProcessor,
359 ServicePathInputData servicePathDataAtoZ,
360 ServicePathInputData servicePathDataZtoA) {
362 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
363 // Do notifications & LOG.info deserve this ?
364 LOG.info(RENDERING_DEVICES_A_Z_MSG);
366 ServicePathNotificationTypes.ServiceImplementationRequest,
367 servicePathDataAtoZ.getServicePathInput().getServiceName(),
369 RENDERING_DEVICES_A_Z_MSG);
370 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
371 this.executor.submit(
372 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z));
374 LOG.info(RENDERING_DEVICES_Z_A_MSG);
376 ServicePathNotificationTypes.ServiceImplementationRequest,
377 servicePathDataZtoA.getServicePathInput().getServiceName(),
379 RENDERING_DEVICES_Z_A_MSG);
380 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
381 this.executor.submit(
382 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A));
384 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
385 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
387 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
389 LOG.info("Waiting for A-Z and Z-A device renderers ...");
390 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
391 } catch (InterruptedException | ExecutionException | TimeoutException e) {
392 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
394 ServicePathNotificationTypes.ServiceImplementationRequest,
395 servicePathDataAtoZ.getServicePathInput().getServiceName(),
397 DEVICE_RENDERING_ROLL_BACK_MSG);
398 //FIXME we can't do rollback here, because we don't have rendering results.
399 return renderingResults;
402 rollbackProcessor.addTask(
403 new DeviceRenderingRollbackTask(
405 ! renderingResults.get(0).isSuccess(),
406 renderingResults.get(0).getRenderedNodeInterfaces(),
407 this.deviceRenderer));
408 rollbackProcessor.addTask(
409 new DeviceRenderingRollbackTask("ZtoADeviceTask",
410 ! renderingResults.get(1).isSuccess(),
411 renderingResults.get(1).getRenderedNodeInterfaces(),
412 this.deviceRenderer));
413 return renderingResults;
416 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
417 value = "UPM_UNCALLED_PRIVATE_METHOD",
418 justification = "call in call() method")
419 private List<OtnDeviceRenderingResult> otnDeviceRendering(
420 RollbackProcessor rollbackProcessor,
421 OtnServicePathInput otnServicePathAtoZ,
422 OtnServicePathInput otnServicePathZtoA,
423 String serviceType) {
425 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
426 // Do notifications & LOG.info deserve this ?
427 LOG.info(RENDERING_DEVICES_A_Z_MSG);
429 ServicePathNotificationTypes.ServiceImplementationRequest,
430 otnServicePathAtoZ.getServiceName(),
432 RENDERING_DEVICES_A_Z_MSG);
433 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
434 this.executor.submit(
435 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
437 LOG.info(RENDERING_DEVICES_Z_A_MSG);
439 ServicePathNotificationTypes.ServiceImplementationRequest,
440 otnServicePathZtoA.getServiceName(),
442 RENDERING_DEVICES_Z_A_MSG);
443 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
444 this.executor.submit(
445 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
447 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
448 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
449 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
451 LOG.info("Waiting for A-Z and Z-A device renderers ...");
452 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
453 } catch (InterruptedException | ExecutionException | TimeoutException e) {
454 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
456 ServicePathNotificationTypes.ServiceImplementationRequest,
457 otnServicePathAtoZ.getServiceName(),
459 DEVICE_RENDERING_ROLL_BACK_MSG);
460 //FIXME we can't do rollback here, because we don't have rendering results.
461 return otnRenderingResults;
463 for (int i = 0; i < otnRenderingResults.size(); i++) {
464 rollbackProcessor.addTask(
465 new DeviceRenderingRollbackTask(
466 "DeviceTask n° " + i + 1,
467 ! otnRenderingResults.get(i).isSuccess(),
468 otnRenderingResults.get(i).getRenderedNodeInterfaces(),
469 this.deviceRenderer));
471 return otnRenderingResults;
474 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
475 value = "UPM_UNCALLED_PRIVATE_METHOD",
476 justification = "call in call() method")
477 private void olmPowerSetup(
478 RollbackProcessor rollbackProcessor,
479 ServicePowerSetupInput powerSetupInputAtoZ,
480 ServicePowerSetupInput powerSetupInputZtoA) {
482 //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
483 // Do notifications & LOG.info deserve this ?
484 //TODO use constants for LOG.info & notifications common messages
485 LOG.info("Olm power setup A-Z");
487 ServicePathNotificationTypes.ServiceImplementationRequest,
488 powerSetupInputAtoZ.getServiceName(),
490 "Olm power setup A-Z");
491 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
492 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
494 LOG.info("OLM power setup Z-A");
496 ServicePathNotificationTypes.ServiceImplementationRequest,
497 powerSetupInputAtoZ.getServiceName(),
499 "Olm power setup Z-A");
500 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
501 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
503 ListenableFuture<List<OLMRenderingResult>> olmFutures =
504 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
506 List<OLMRenderingResult> olmResults;
508 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
509 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
510 } catch (InterruptedException | ExecutionException | TimeoutException e) {
511 LOG.warn(OLM_ROLL_BACK_MSG, e);
513 ServicePathNotificationTypes.ServiceImplementationRequest,
514 powerSetupInputAtoZ.getServiceName(),
517 rollbackProcessor.addTask(
518 new OlmPowerSetupRollbackTask("AtoZOLMTask", true, this.olmService, powerSetupInputAtoZ));
519 rollbackProcessor.addTask(
520 new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, this.olmService, powerSetupInputZtoA));
524 rollbackProcessor.addTask(
525 new OlmPowerSetupRollbackTask(
527 ! olmResults.get(0).isSuccess(),
529 powerSetupInputAtoZ));
530 rollbackProcessor.addTask(
531 new OlmPowerSetupRollbackTask(
533 ! olmResults.get(1).isSuccess(),
535 powerSetupInputZtoA));
538 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
539 value = "UPM_UNCALLED_PRIVATE_METHOD",
540 justification = "call in call() method")
541 private boolean isServiceActivated(String nodeId, String tpId) {
542 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
543 for (int i = 0; i < 3; i++) {
544 List<Measurements> measurements = getMeasurements(nodeId, tpId);
545 if (measurements == null) {
546 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
549 if (verifyPreFecBer(measurements)) {
553 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
554 } catch (InterruptedException ex) {
555 Thread.currentThread().interrupt();
558 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
562 private List<Measurements> getMeasurements(String nodeId, String tp) {
564 GetPmOutput getPmOutput =
567 new GetPmInputBuilder()
569 .setGranularity(PmGranularity._15min)
570 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
571 .setResourceType(ResourceTypeEnum.Interface)
575 if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
576 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
578 LOG.info("successfully finished calling OLM's get PM");
579 return getPmOutput.getMeasurements();
583 } catch (ExecutionException | InterruptedException e) {
584 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
589 private boolean verifyPreFecBer(List<Measurements> measurements) {
590 double preFecCorrectedErrors = Double.MIN_VALUE;
591 double fecUncorrectableBlocks = Double.MIN_VALUE;
593 for (Measurements measurement : measurements) {
594 switch (measurement.getPmparameterName()) {
595 case "preFECCorrectedErrors":
596 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
598 case "FECUncorrectableBlocks":
599 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
606 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
607 preFecCorrectedErrors, fecUncorrectableBlocks);
609 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
610 LOG.error("Data has uncorrectable errors, BER test failed");
614 double numOfBitsPerSecond = 112000000000d;
615 double threshold = 0.00002d;
616 double result = preFecCorrectedErrors / numOfBitsPerSecond;
617 LOG.info("PreFEC value is {}", Double.toString(result));
618 return result <= threshold;
621 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
622 value = "UPM_UNCALLED_PRIVATE_METHOD",
623 justification = "call in call() method")
624 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
625 ServicePathInputData servicePathInputDataAtoZ =
627 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
628 ServicePathInputData servicePathInputDataZtoA =
630 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
631 // Rollback should be same for all conditions, so creating a new one
632 RollbackProcessor rollbackProcessor = new RollbackProcessor();
633 List<DeviceRenderingResult> renderingResults =
634 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
635 if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
637 ServicePathNotificationTypes.ServiceImplementationRequest,
638 input.getServiceName(),
640 DEVICE_RENDERING_ROLL_BACK_MSG);
645 //olmPowerSetupInputAtoZ,
646 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
647 //olmPowerSetupInputZtoA
648 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input));
649 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
651 ServicePathNotificationTypes.ServiceImplementationRequest,
652 input.getServiceName(),
657 // run service activation test twice - once on source node and once on
659 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
660 if ((nodes == null) || (nodes.isEmpty())) {
664 Nodes sourceNode = nodes.get(0);
665 Nodes destNode = nodes.get(nodes.size() - 1);
666 String srcNetworkTp =
667 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
668 ? sourceNode.getDestTp()
669 : sourceNode.getSrcTp();
670 String dstNetowrkTp =
671 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
672 ? destNode.getDestTp()
673 : destNode.getSrcTp();
675 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
676 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
677 rollbackProcessor.rollbackAll();
679 ServicePathNotificationTypes.ServiceImplementationRequest,
680 input.getServiceName(),
682 "Service activation test failed.");
685 sendNotificationsWithPathDescription(
686 ServicePathNotificationTypes.ServiceImplementationRequest,
687 input.getServiceName(),
688 RpcStatusEx.Successful,
689 OPERATION_SUCCESSFUL,
690 input.getPathDescription(),
692 renderingResults.stream()
693 .flatMap(rr -> rr.getOtnLinkTps().stream())
694 .collect(Collectors.toList())),
700 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
701 value = "UPM_UNCALLED_PRIVATE_METHOD",
702 justification = "call in call() method")
703 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
704 throws InterruptedException {
705 ServicePathInputData servicePathInputDataAtoZ =
706 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
707 ServicePathInputData servicePathInputDataZtoA =
708 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
709 // OLM turn down power
711 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
713 ServicePathNotificationTypes.ServiceDelete,
716 TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
717 // TODO add some flag rather than string
719 olmPowerTurndown(servicePathInputDataAtoZ)
721 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
723 ServicePathNotificationTypes.ServiceDelete,
726 "Service power turndown failed on A-to-Z path for service");
729 LOG.debug("Turning down power on Z-to-A path");
731 ServicePathNotificationTypes.ServiceDelete,
734 "Turning down power on Z-to-A path");
735 // TODO add some flag rather than string
737 olmPowerTurndown(servicePathInputDataZtoA)
739 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
741 ServicePathNotificationTypes.ServiceDelete,
744 "Service power turndown failed on Z-to-A path for service");
747 } catch (InterruptedException | ExecutionException | TimeoutException e) {
748 LOG.error("Error while turning down power!", e);
751 // delete service path with renderer
752 LOG.info("Deleting service path via renderer");
754 ServicePathNotificationTypes.ServiceDelete,
757 "Deleting service path via renderer");
758 sendNotificationsWithPathDescription(
759 ServicePathNotificationTypes.ServiceDelete,
761 RpcStatusEx.Successful,
762 OPERATION_SUCCESSFUL,
766 new RollbackProcessor(),
767 servicePathInputDataAtoZ,
768 servicePathInputDataZtoA)
770 .flatMap(rr -> rr.getOtnLinkTps().stream())
771 .collect(Collectors.toList())),
777 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
778 value = "UPM_UNCALLED_PRIVATE_METHOD",
779 justification = "call in call() method")
780 private boolean manageOtnServicePathCreation(
781 ServiceImplementationRequestInput input,
783 Uint32 serviceRate) {
784 // Rollback should be same for all conditions, so creating a new one
785 RollbackProcessor rollbackProcessor = new RollbackProcessor();
786 List<OtnDeviceRenderingResult> renderingResults =
791 .rendererCreateOtnServiceInput(
792 input.getServiceName(),
794 input.getServiceAEnd().getServiceFormat().getName(),
796 input.getPathDescription(),
800 .rendererCreateOtnServiceInput(
801 input.getServiceName(),
803 input.getServiceZEnd().getServiceFormat().getName(),
805 input.getPathDescription(),
808 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
809 rollbackProcessor.rollbackAll();
811 ServicePathNotificationTypes.ServiceImplementationRequest,
812 input.getServiceName(),
814 DEVICE_RENDERING_ROLL_BACK_MSG);
817 sendNotificationsWithPathDescription(
818 ServicePathNotificationTypes.ServiceImplementationRequest,
819 input.getServiceName(),
820 RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
821 input.getPathDescription(),
823 renderingResults.stream()
824 .flatMap(rr -> rr.getOtnLinkTps().stream())
825 .collect(Collectors.toList())),
827 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
833 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
834 value = "UPM_UNCALLED_PRIVATE_METHOD",
835 justification = "call in call() method")
836 private boolean manageOtnServicePathDeletion(
838 PathDescription pathDescription,
840 String serviceType) {
841 LOG.info("Deleting otn-service path {} via renderer", serviceName);
843 ServicePathNotificationTypes.ServiceDelete,
846 "Deleting otn-service path via renderer");
847 List<OtnDeviceRenderingResult> renderingResults =
849 new RollbackProcessor(),
852 .rendererCreateOtnServiceInput(
855 service.getServiceAEnd().getServiceFormat().getName(),
856 service.getServiceAEnd().getServiceRate(),
861 .rendererCreateOtnServiceInput(
864 service.getServiceZEnd().getServiceFormat().getName(),
865 service.getServiceAEnd().getServiceRate(),
869 sendNotificationsWithPathDescription(
870 ServicePathNotificationTypes.ServiceDelete,
872 RpcStatusEx.Successful,
873 OPERATION_SUCCESSFUL,
876 renderingResults.stream()
877 .flatMap(rr -> rr.getOtnLinkTps().stream())
878 .collect(Collectors.toList())),
880 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
887 * Send renderer notification.
888 * @param servicePathNotificationTypes ServicePathNotificationTypes
889 * @param serviceName String
890 * @param rpcStatusEx RpcStatusEx
891 * @param message String
893 private void sendNotifications(
894 ServicePathNotificationTypes servicePathNotificationTypes,
896 RpcStatusEx rpcStatusEx,
899 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
900 null, null, null, null));
904 * Send renderer notification with path description information.
905 * @param servicePathNotificationTypes ServicePathNotificationTypes
906 * @param serviceName String
907 * @param rpcStatusEx RpcStatusEx
908 * @param message String
909 * @param pathDescription PathDescription
911 private void sendNotificationsWithPathDescription(
912 ServicePathNotificationTypes servicePathNotificationTypes,
914 RpcStatusEx rpcStatusEx,
916 PathDescription pathDescription,
918 Set<String> supportedLinks,
919 String serviceType) {
921 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
922 pathDescription, notifLink, supportedLinks, serviceType));
926 * Build notification containing path description information.
927 * @param servicePathNotificationTypes ServicePathNotificationTypes
928 * @param serviceName String
929 * @param rpcStatusEx RpcStatusEx
930 * @param message String
931 * @param pathDescription PathDescription
932 * @return notification with RendererRpcResultSp type.
934 private RendererRpcResultSp buildNotification(
935 ServicePathNotificationTypes servicePathNotificationTypes,
937 RpcStatusEx rpcStatusEx,
939 PathDescription pathDescription,
941 Set<String> supportedLinks,
942 String serviceType) {
943 RendererRpcResultSpBuilder builder =
944 new RendererRpcResultSpBuilder()
945 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
946 .setStatusMessage(message)
947 .setServiceType(serviceType);
948 if (pathDescription != null) {
950 .setAToZDirection(pathDescription.getAToZDirection())
951 .setZToADirection(pathDescription.getZToADirection());
953 if (notifLink != null) {
954 builder.setLink(notifLink);
956 if (supportedLinks != null) {
957 builder.setLinkId(supportedLinks);
959 return builder.build();
963 * Send renderer notification.
964 * @param notification Notification
966 private void send(Notification<?> notification) {
968 LOG.info("Sending notification {}", notification);
969 notificationPublishService.putNotification(notification);
970 } catch (InterruptedException e) {
971 LOG.info("notification offer rejected: ", e);
972 Thread.currentThread().interrupt();
976 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
978 otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
982 new ATerminationBuilder()
983 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
984 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
987 new ZTerminationBuilder()
988 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
989 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
994 private Set<String> getSupportedLinks(Set<String> allSupportLinks, String serviceType) {
995 //TODO a Map might be more indicated here
996 switch (serviceType) {
997 case StringConstants.SERVICE_TYPE_10GE:
998 case StringConstants.SERVICE_TYPE_1GE:
999 return allSupportLinks.stream()
1000 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toSet());
1001 case StringConstants.SERVICE_TYPE_100GE_M:
1002 return allSupportLinks.stream()
1003 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toSet());
1004 case StringConstants.SERVICE_TYPE_ODU4:
1005 case StringConstants.SERVICE_TYPE_100GE_S:
1006 return allSupportLinks.stream()
1007 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toSet());
1008 case StringConstants.SERVICE_TYPE_ODUC4:
1009 return allSupportLinks.stream()
1010 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toSet());