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.pm.types.rev161014.PmGranularity;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
66 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.PathDescription;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.link.tp.LinkTp;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.olm.get.pm.input.ResourceIdentifierBuilder;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.optical.renderer.nodes.Nodes;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.opendaylight.yangtools.yang.binding.Notification;
78 import org.opendaylight.yangtools.yang.common.Uint32;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
83 public class RendererServiceOperationsImpl implements RendererServiceOperations {
85 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
86 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
87 "Device rendering was not successful! Rendering will be rolled back.";
88 private static final String OLM_ROLL_BACK_MSG =
89 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
90 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
91 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
92 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
93 private static final String FAILED = "Failed";
94 private static final String OPERATION_FAILED = "Operation Failed";
95 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
96 private static final int NUMBER_OF_THREADS = 4;
98 private final DeviceRendererService deviceRenderer;
99 private final OtnDeviceRendererService otnDeviceRenderer;
100 private final TransportpceOlmService olmService;
101 private final DataBroker dataBroker;
102 private final NotificationPublishService notificationPublishService;
103 private final PortMapping portMapping;
104 private ListeningExecutorService executor;
106 public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
107 OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
108 DataBroker dataBroker, NotificationPublishService notificationPublishService, PortMapping portMapping) {
109 this.deviceRenderer = deviceRenderer;
110 this.otnDeviceRenderer = otnDeviceRenderer;
111 this.olmService = olmService;
112 this.dataBroker = dataBroker;
113 this.notificationPublishService = notificationPublishService;
114 this.portMapping = portMapping;
115 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
119 public ListenableFuture<ServiceImplementationRequestOutput>
120 serviceImplementation(ServiceImplementationRequestInput input) {
121 LOG.info("Calling service impl request {}", input.getServiceName());
122 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
125 public ServiceImplementationRequestOutput call() throws Exception {
127 ServicePathNotificationTypes.ServiceImplementationRequest,
128 input.getServiceName(),
130 "Service compliant, submitting service implementation Request ...");
131 Uint32 serviceRate = getServiceRate(input);
132 LOG.info("Using {}G rate", serviceRate);
133 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220316
134 .network.Nodes mappingNode =
135 portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
136 ? portMapping.getNode(input.getServiceAEnd().getNodeId())
138 String serviceType = ServiceTypes.getServiceType(
139 input.getServiceAEnd().getServiceFormat().getName(),
142 && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
143 && input.getServiceAEnd().getTxDirection() != null
144 && input.getServiceAEnd().getTxDirection().getPort() != null
145 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
146 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
147 input.getServiceAEnd().getTxDirection().getPort().getPortName())
149 //TODO a Map might be more indicated here
150 switch (serviceType) {
151 case StringConstants.SERVICE_TYPE_100GE_T:
152 case StringConstants.SERVICE_TYPE_400GE:
153 case StringConstants.SERVICE_TYPE_OTU4:
154 case StringConstants.SERVICE_TYPE_OTUC2:
155 case StringConstants.SERVICE_TYPE_OTUC3:
156 case StringConstants.SERVICE_TYPE_OTUC4:
157 if (!manageServicePathCreation(input, serviceType)) {
158 return ModelMappingUtils
159 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
162 case StringConstants.SERVICE_TYPE_1GE:
163 case StringConstants.SERVICE_TYPE_10GE:
164 case StringConstants.SERVICE_TYPE_100GE_M:
165 case StringConstants.SERVICE_TYPE_100GE_S:
166 case StringConstants.SERVICE_TYPE_ODU4:
167 case StringConstants.SERVICE_TYPE_ODUC2:
168 case StringConstants.SERVICE_TYPE_ODUC3:
169 case StringConstants.SERVICE_TYPE_ODUC4:
170 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
171 return ModelMappingUtils
172 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
176 LOG.error("unsupported service-type");
177 return ModelMappingUtils
178 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
180 return ModelMappingUtils
181 .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
187 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
188 String serviceName = input.getServiceName();
189 LOG.info("Calling service delete request {}", serviceName);
190 return executor.submit(new Callable<ServiceDeleteOutput>() {
193 public ServiceDeleteOutput call() throws Exception {
195 ServicePathNotificationTypes.ServiceDelete,
198 "Service compliant, submitting service delete Request ...");
199 // Obtain path description
201 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
202 .service.path.PathDescription> pathDescriptionOpt =
203 getPathDescriptionFromDatastore(serviceName);
204 if (pathDescriptionOpt.isEmpty()) {
205 LOG.error("Unable to get path description for service {}!", serviceName);
207 ServicePathNotificationTypes.ServiceDelete,
210 "Unable to get path description for service");
211 return ModelMappingUtils
212 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
214 PathDescription pathDescription = pathDescriptionOpt.get();
216 ServiceTypes.getServiceType(
217 service.getServiceAEnd().getServiceFormat().getName(),
218 service.getServiceAEnd().getServiceRate(),
219 service.getServiceAEnd().getTxDirection() == null
220 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
222 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
223 .getPort().getPortName() == null
225 : portMapping.getMapping(
226 service.getServiceAEnd().getNodeId().getValue(),
227 service.getServiceAEnd().getTxDirection().values().stream().findFirst().get()
228 .getPort().getPortName()));
229 switch (serviceType) {
230 case StringConstants.SERVICE_TYPE_100GE_T:
231 case StringConstants.SERVICE_TYPE_400GE:
232 case StringConstants.SERVICE_TYPE_OTU4:
233 case StringConstants.SERVICE_TYPE_OTUC2:
234 case StringConstants.SERVICE_TYPE_OTUC3:
235 case StringConstants.SERVICE_TYPE_OTUC4:
236 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
237 return ModelMappingUtils
238 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
241 case StringConstants.SERVICE_TYPE_1GE:
242 case StringConstants.SERVICE_TYPE_10GE:
243 case StringConstants.SERVICE_TYPE_100GE_M:
244 case StringConstants.SERVICE_TYPE_100GE_S:
245 case StringConstants.SERVICE_TYPE_ODU4:
246 case StringConstants.SERVICE_TYPE_ODUC2:
247 case StringConstants.SERVICE_TYPE_ODUC3:
248 case StringConstants.SERVICE_TYPE_ODUC4:
249 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
250 return ModelMappingUtils
251 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
255 LOG.error("unsupported service-type");
256 return ModelMappingUtils
257 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
259 return ModelMappingUtils
260 .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
265 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
266 value = "UPM_UNCALLED_PRIVATE_METHOD",
267 justification = "call in call() method")
268 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
269 if (input.getServiceAEnd() == null) {
270 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
273 if (input.getServiceAEnd().getServiceRate() != null) {
274 return input.getServiceAEnd().getServiceRate();
276 LOG.warn("Input should have rate if you are using 200 or 300G");
277 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
278 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
279 ServiceFormat.OTU, Map.of(
280 "OTUCn", Uint32.valueOf(400),
281 "OTU4", Uint32.valueOf(100),
282 "OTU2", Uint32.valueOf(10),
283 "OTU2e", Uint32.valueOf(10)),
284 ServiceFormat.ODU, Map.of(
285 "ODUCn",Uint32.valueOf(400),
286 "ODU4", Uint32.valueOf(100),
287 "ODU2", Uint32.valueOf(10),
288 "ODU2e", Uint32.valueOf(10),
289 "ODU0", Uint32.valueOf(1)));
290 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
291 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
292 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
296 ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
297 ? input.getServiceAEnd().getOtuServiceRate().toString().split("\\{")[0]
298 : input.getServiceAEnd().getOduServiceRate().toString().split("\\{")[0];
299 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
300 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
301 input.getServiceName(), serviceName);
305 .get(input.getServiceAEnd().getServiceFormat())
309 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
310 value = "UPM_UNCALLED_PRIVATE_METHOD",
311 justification = "call in call() method")
312 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
313 throws InterruptedException, ExecutionException, TimeoutException {
314 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
315 return this.olmService
316 .servicePowerTurndown(
317 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build())
318 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS)
322 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
323 value = "UPM_UNCALLED_PRIVATE_METHOD",
324 justification = "call in call() method")
325 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
326 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
327 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
328 .service.path.PathDescription> pathDescriptionIID =
329 InstanceIdentifier.create(ServicePathList.class)
330 .child(ServicePaths.class, new ServicePathsKey(serviceName))
331 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
332 .service.path.PathDescription.class);
334 LOG.debug("Getting path description for service {}", serviceName);
335 return this.dataBroker.newReadOnlyTransaction()
336 .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
337 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
338 } catch (InterruptedException | ExecutionException | TimeoutException e) {
339 LOG.warn("Exception while getting path description from datastore {} for service {}!",
340 pathDescriptionIID, serviceName, e);
341 return Optional.empty();
345 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
346 value = "UPM_UNCALLED_PRIVATE_METHOD",
347 justification = "call in call() method")
348 private List<DeviceRenderingResult> deviceRendering(
349 RollbackProcessor rollbackProcessor,
350 ServicePathInputData servicePathDataAtoZ,
351 ServicePathInputData servicePathDataZtoA) {
353 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
354 // Do notifications & LOG.info deserve this ?
355 LOG.info(RENDERING_DEVICES_A_Z_MSG);
357 ServicePathNotificationTypes.ServiceImplementationRequest,
358 servicePathDataAtoZ.getServicePathInput().getServiceName(),
360 RENDERING_DEVICES_A_Z_MSG);
361 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
362 this.executor.submit(
363 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z));
365 LOG.info(RENDERING_DEVICES_Z_A_MSG);
367 ServicePathNotificationTypes.ServiceImplementationRequest,
368 servicePathDataZtoA.getServicePathInput().getServiceName(),
370 RENDERING_DEVICES_Z_A_MSG);
371 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
372 this.executor.submit(
373 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A));
375 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
376 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
378 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
380 LOG.info("Waiting for A-Z and Z-A device renderers ...");
381 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
382 } catch (InterruptedException | ExecutionException | TimeoutException e) {
383 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
385 ServicePathNotificationTypes.ServiceImplementationRequest,
386 servicePathDataAtoZ.getServicePathInput().getServiceName(),
388 DEVICE_RENDERING_ROLL_BACK_MSG);
389 //FIXME we can't do rollback here, because we don't have rendering results.
390 return renderingResults;
393 rollbackProcessor.addTask(
394 new DeviceRenderingRollbackTask(
396 ! renderingResults.get(0).isSuccess(),
397 renderingResults.get(0).getRenderedNodeInterfaces(),
398 this.deviceRenderer));
399 rollbackProcessor.addTask(
400 new DeviceRenderingRollbackTask("ZtoADeviceTask",
401 ! renderingResults.get(1).isSuccess(),
402 renderingResults.get(1).getRenderedNodeInterfaces(),
403 this.deviceRenderer));
404 return renderingResults;
407 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
408 value = "UPM_UNCALLED_PRIVATE_METHOD",
409 justification = "call in call() method")
410 private List<OtnDeviceRenderingResult> otnDeviceRendering(
411 RollbackProcessor rollbackProcessor,
412 OtnServicePathInput otnServicePathAtoZ,
413 OtnServicePathInput otnServicePathZtoA,
414 String serviceType) {
416 //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
417 // Do notifications & LOG.info deserve this ?
418 LOG.info(RENDERING_DEVICES_A_Z_MSG);
420 ServicePathNotificationTypes.ServiceImplementationRequest,
421 otnServicePathAtoZ.getServiceName(),
423 RENDERING_DEVICES_A_Z_MSG);
424 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
425 this.executor.submit(
426 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
428 LOG.info(RENDERING_DEVICES_Z_A_MSG);
430 ServicePathNotificationTypes.ServiceImplementationRequest,
431 otnServicePathZtoA.getServiceName(),
433 RENDERING_DEVICES_Z_A_MSG);
434 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
435 this.executor.submit(
436 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
438 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
439 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
440 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
442 LOG.info("Waiting for A-Z and Z-A device renderers ...");
443 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
444 } catch (InterruptedException | ExecutionException | TimeoutException e) {
445 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
447 ServicePathNotificationTypes.ServiceImplementationRequest,
448 otnServicePathAtoZ.getServiceName(),
450 DEVICE_RENDERING_ROLL_BACK_MSG);
451 //FIXME we can't do rollback here, because we don't have rendering results.
452 return otnRenderingResults;
454 for (int i = 0; i < otnRenderingResults.size(); i++) {
455 rollbackProcessor.addTask(
456 new DeviceRenderingRollbackTask(
457 "DeviceTask n° " + i + 1,
458 ! otnRenderingResults.get(i).isSuccess(),
459 otnRenderingResults.get(i).getRenderedNodeInterfaces(),
460 this.deviceRenderer));
462 return otnRenderingResults;
465 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
466 value = "UPM_UNCALLED_PRIVATE_METHOD",
467 justification = "call in call() method")
468 private void olmPowerSetup(
469 RollbackProcessor rollbackProcessor,
470 ServicePowerSetupInput powerSetupInputAtoZ,
471 ServicePowerSetupInput powerSetupInputZtoA) {
473 //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
474 // Do notifications & LOG.info deserve this ?
475 //TODO use constants for LOG.info & notifications common messages
476 LOG.info("Olm power setup A-Z");
478 ServicePathNotificationTypes.ServiceImplementationRequest,
479 powerSetupInputAtoZ.getServiceName(),
481 "Olm power setup A-Z");
482 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
483 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
485 LOG.info("OLM power setup Z-A");
487 ServicePathNotificationTypes.ServiceImplementationRequest,
488 powerSetupInputAtoZ.getServiceName(),
490 "Olm power setup Z-A");
491 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
492 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
494 ListenableFuture<List<OLMRenderingResult>> olmFutures =
495 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
497 List<OLMRenderingResult> olmResults;
499 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
500 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
501 } catch (InterruptedException | ExecutionException | TimeoutException e) {
502 LOG.warn(OLM_ROLL_BACK_MSG, e);
504 ServicePathNotificationTypes.ServiceImplementationRequest,
505 powerSetupInputAtoZ.getServiceName(),
508 rollbackProcessor.addTask(
509 new OlmPowerSetupRollbackTask("AtoZOLMTask", true, this.olmService, powerSetupInputAtoZ));
510 rollbackProcessor.addTask(
511 new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, this.olmService, powerSetupInputZtoA));
515 rollbackProcessor.addTask(
516 new OlmPowerSetupRollbackTask(
518 ! olmResults.get(0).isSuccess(),
520 powerSetupInputAtoZ));
521 rollbackProcessor.addTask(
522 new OlmPowerSetupRollbackTask(
524 ! olmResults.get(1).isSuccess(),
526 powerSetupInputZtoA));
529 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
530 value = "UPM_UNCALLED_PRIVATE_METHOD",
531 justification = "call in call() method")
532 private boolean isServiceActivated(String nodeId, String tpId) {
533 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
534 for (int i = 0; i < 3; i++) {
535 List<Measurements> measurements = getMeasurements(nodeId, tpId);
536 if (measurements == null) {
537 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
540 if (verifyPreFecBer(measurements)) {
544 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
545 } catch (InterruptedException ex) {
546 Thread.currentThread().interrupt();
549 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
553 private List<Measurements> getMeasurements(String nodeId, String tp) {
555 GetPmOutput getPmOutput =
558 new GetPmInputBuilder()
560 .setGranularity(PmGranularity._15min)
561 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
562 .setResourceType(ResourceTypeEnum.Interface)
566 if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
567 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
569 LOG.info("successfully finished calling OLM's get PM");
570 return getPmOutput.getMeasurements();
574 } catch (ExecutionException | InterruptedException e) {
575 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
580 private boolean verifyPreFecBer(List<Measurements> measurements) {
581 double preFecCorrectedErrors = Double.MIN_VALUE;
582 double fecUncorrectableBlocks = Double.MIN_VALUE;
584 for (Measurements measurement : measurements) {
585 switch (measurement.getPmparameterName()) {
586 case "preFECCorrectedErrors":
587 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
589 case "FECUncorrectableBlocks":
590 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
597 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
598 preFecCorrectedErrors, fecUncorrectableBlocks);
600 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
601 LOG.error("Data has uncorrectable errors, BER test failed");
605 double numOfBitsPerSecond = 112000000000d;
606 double threshold = 0.00002d;
607 double result = preFecCorrectedErrors / numOfBitsPerSecond;
608 LOG.info("PreFEC value is {}", Double.toString(result));
609 return result <= threshold;
612 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
613 value = "UPM_UNCALLED_PRIVATE_METHOD",
614 justification = "call in call() method")
615 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
616 ServicePathInputData servicePathInputDataAtoZ =
618 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
619 ServicePathInputData servicePathInputDataZtoA =
621 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
622 // Rollback should be same for all conditions, so creating a new one
623 RollbackProcessor rollbackProcessor = new RollbackProcessor();
624 List<DeviceRenderingResult> renderingResults =
625 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
626 if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
628 ServicePathNotificationTypes.ServiceImplementationRequest,
629 input.getServiceName(),
631 DEVICE_RENDERING_ROLL_BACK_MSG);
636 //olmPowerSetupInputAtoZ,
637 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
638 //olmPowerSetupInputZtoA
639 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input));
640 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
642 ServicePathNotificationTypes.ServiceImplementationRequest,
643 input.getServiceName(),
648 // run service activation test twice - once on source node and once on
650 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
651 if ((nodes == null) || (nodes.isEmpty())) {
655 Nodes sourceNode = nodes.get(0);
656 Nodes destNode = nodes.get(nodes.size() - 1);
657 String srcNetworkTp =
658 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
659 ? sourceNode.getDestTp()
660 : sourceNode.getSrcTp();
661 String dstNetowrkTp =
662 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
663 ? destNode.getDestTp()
664 : destNode.getSrcTp();
666 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
667 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
668 rollbackProcessor.rollbackAll();
670 ServicePathNotificationTypes.ServiceImplementationRequest,
671 input.getServiceName(),
673 "Service activation test failed.");
676 sendNotificationsWithPathDescription(
677 ServicePathNotificationTypes.ServiceImplementationRequest,
678 input.getServiceName(),
679 RpcStatusEx.Successful,
680 OPERATION_SUCCESSFUL,
681 input.getPathDescription(),
683 renderingResults.stream()
684 .flatMap(rr -> rr.getOtnLinkTps().stream())
685 .collect(Collectors.toList())),
691 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
692 value = "UPM_UNCALLED_PRIVATE_METHOD",
693 justification = "call in call() method")
694 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
695 throws InterruptedException {
696 ServicePathInputData servicePathInputDataAtoZ =
697 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
698 ServicePathInputData servicePathInputDataZtoA =
699 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
700 // OLM turn down power
702 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
704 ServicePathNotificationTypes.ServiceDelete,
707 TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
708 // TODO add some flag rather than string
710 olmPowerTurndown(servicePathInputDataAtoZ)
712 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
714 ServicePathNotificationTypes.ServiceDelete,
717 "Service power turndown failed on A-to-Z path for service");
720 LOG.debug("Turning down power on Z-to-A path");
722 ServicePathNotificationTypes.ServiceDelete,
725 "Turning down power on Z-to-A path");
726 // TODO add some flag rather than string
728 olmPowerTurndown(servicePathInputDataZtoA)
730 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
732 ServicePathNotificationTypes.ServiceDelete,
735 "Service power turndown failed on Z-to-A path for service");
738 } catch (InterruptedException | ExecutionException | TimeoutException e) {
739 LOG.error("Error while turning down power!", e);
742 // delete service path with renderer
743 LOG.info("Deleting service path via renderer");
745 ServicePathNotificationTypes.ServiceDelete,
748 "Deleting service path via renderer");
749 sendNotificationsWithPathDescription(
750 ServicePathNotificationTypes.ServiceDelete,
752 RpcStatusEx.Successful,
753 OPERATION_SUCCESSFUL,
757 new RollbackProcessor(),
758 servicePathInputDataAtoZ,
759 servicePathInputDataZtoA)
761 .flatMap(rr -> rr.getOtnLinkTps().stream())
762 .collect(Collectors.toList())),
768 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
769 value = "UPM_UNCALLED_PRIVATE_METHOD",
770 justification = "call in call() method")
771 private boolean manageOtnServicePathCreation(
772 ServiceImplementationRequestInput input,
774 Uint32 serviceRate) {
775 // Rollback should be same for all conditions, so creating a new one
776 RollbackProcessor rollbackProcessor = new RollbackProcessor();
777 List<OtnDeviceRenderingResult> renderingResults =
782 .rendererCreateOtnServiceInput(
783 input.getServiceName(),
785 input.getServiceAEnd().getServiceFormat().getName(),
787 input.getPathDescription(),
791 .rendererCreateOtnServiceInput(
792 input.getServiceName(),
794 input.getServiceZEnd().getServiceFormat().getName(),
796 input.getPathDescription(),
799 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
800 rollbackProcessor.rollbackAll();
802 ServicePathNotificationTypes.ServiceImplementationRequest,
803 input.getServiceName(),
805 DEVICE_RENDERING_ROLL_BACK_MSG);
808 sendNotificationsWithPathDescription(
809 ServicePathNotificationTypes.ServiceImplementationRequest,
810 input.getServiceName(),
811 RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
812 input.getPathDescription(),
814 renderingResults.stream()
815 .flatMap(rr -> rr.getOtnLinkTps().stream())
816 .collect(Collectors.toList())),
818 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
824 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
825 value = "UPM_UNCALLED_PRIVATE_METHOD",
826 justification = "call in call() method")
827 private boolean manageOtnServicePathDeletion(
829 PathDescription pathDescription,
831 String serviceType) {
832 LOG.info("Deleting otn-service path {} via renderer", serviceName);
834 ServicePathNotificationTypes.ServiceDelete,
837 "Deleting otn-service path via renderer");
838 List<OtnDeviceRenderingResult> renderingResults =
840 new RollbackProcessor(),
843 .rendererCreateOtnServiceInput(
846 service.getServiceAEnd().getServiceFormat().getName(),
847 service.getServiceAEnd().getServiceRate(),
852 .rendererCreateOtnServiceInput(
855 service.getServiceZEnd().getServiceFormat().getName(),
856 service.getServiceAEnd().getServiceRate(),
860 sendNotificationsWithPathDescription(
861 ServicePathNotificationTypes.ServiceDelete,
863 RpcStatusEx.Successful,
864 OPERATION_SUCCESSFUL,
867 renderingResults.stream()
868 .flatMap(rr -> rr.getOtnLinkTps().stream())
869 .collect(Collectors.toList())),
871 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
878 * Send renderer notification.
879 * @param servicePathNotificationTypes ServicePathNotificationTypes
880 * @param serviceName String
881 * @param rpcStatusEx RpcStatusEx
882 * @param message String
884 private void sendNotifications(
885 ServicePathNotificationTypes servicePathNotificationTypes,
887 RpcStatusEx rpcStatusEx,
890 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
891 null, null, null, null));
895 * Send renderer notification with path description information.
896 * @param servicePathNotificationTypes ServicePathNotificationTypes
897 * @param serviceName String
898 * @param rpcStatusEx RpcStatusEx
899 * @param message String
900 * @param pathDescription PathDescription
902 private void sendNotificationsWithPathDescription(
903 ServicePathNotificationTypes servicePathNotificationTypes,
905 RpcStatusEx rpcStatusEx,
907 PathDescription pathDescription,
909 Set<String> supportedLinks,
910 String serviceType) {
912 buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
913 pathDescription, notifLink, supportedLinks, serviceType));
917 * Build notification containing path description information.
918 * @param servicePathNotificationTypes ServicePathNotificationTypes
919 * @param serviceName String
920 * @param rpcStatusEx RpcStatusEx
921 * @param message String
922 * @param pathDescription PathDescription
923 * @return notification with RendererRpcResultSp type.
925 private RendererRpcResultSp buildNotification(
926 ServicePathNotificationTypes servicePathNotificationTypes,
928 RpcStatusEx rpcStatusEx,
930 PathDescription pathDescription,
932 Set<String> supportedLinks,
933 String serviceType) {
934 RendererRpcResultSpBuilder builder =
935 new RendererRpcResultSpBuilder()
936 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
937 .setStatusMessage(message)
938 .setServiceType(serviceType);
939 if (pathDescription != null) {
941 .setAToZDirection(pathDescription.getAToZDirection())
942 .setZToADirection(pathDescription.getZToADirection());
944 if (notifLink != null) {
945 builder.setLink(notifLink);
947 if (supportedLinks != null) {
948 builder.setLinkId(supportedLinks);
950 return builder.build();
954 * Send renderer notification.
955 * @param notification Notification
957 private void send(Notification<?> notification) {
959 LOG.info("Sending notification {}", notification);
960 notificationPublishService.putNotification(notification);
961 } catch (InterruptedException e) {
962 LOG.info("notification offer rejected: ", e);
963 Thread.currentThread().interrupt();
967 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
969 otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
973 new ATerminationBuilder()
974 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
975 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
978 new ZTerminationBuilder()
979 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
980 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
985 private Set<String> getSupportedLinks(Set<String> allSupportLinks, String serviceType) {
986 //TODO a Map might be more indicated here
987 switch (serviceType) {
988 case StringConstants.SERVICE_TYPE_10GE:
989 case StringConstants.SERVICE_TYPE_1GE:
990 return allSupportLinks.stream()
991 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toSet());
992 case StringConstants.SERVICE_TYPE_100GE_M:
993 return allSupportLinks.stream()
994 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toSet());
995 case StringConstants.SERVICE_TYPE_ODU4:
996 case StringConstants.SERVICE_TYPE_100GE_S:
997 return allSupportLinks.stream()
998 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toSet());
999 case StringConstants.SERVICE_TYPE_ODUC4:
1000 return allSupportLinks.stream()
1001 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toSet());