2 * Copyright © 2017 AT&T and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.transportpce.renderer.provisiondevice;
10 import com.google.common.util.concurrent.Futures;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import com.google.common.util.concurrent.ListeningExecutorService;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import java.util.ArrayList;
15 import java.util.List;
17 import java.util.Optional;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24 import java.util.stream.Collectors;
25 import org.opendaylight.mdsal.binding.api.DataBroker;
26 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
27 import org.opendaylight.mdsal.binding.api.ReadTransaction;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.transportpce.common.ResponseCodes;
30 import org.opendaylight.transportpce.common.StringConstants;
31 import org.opendaylight.transportpce.common.Timeouts;
32 import org.opendaylight.transportpce.common.mapping.PortMapping;
33 import org.opendaylight.transportpce.common.service.ServiceTypes;
34 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
35 import org.opendaylight.transportpce.renderer.ServicePathInputData;
36 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
42 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownInputBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220114.mapping.Mapping;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSp;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSpBuilder;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
61 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
62 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
63 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
66 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
67 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.PathDescription;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.ServicePathNotificationTypes;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.link.tp.LinkTp;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.olm.get.pm.input.ResourceIdentifierBuilder;
76 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.optical.renderer.nodes.Nodes;
77 import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev220123.OtnLinkType;
78 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
79 import org.opendaylight.yangtools.yang.binding.Notification;
80 import org.opendaylight.yangtools.yang.common.RpcResult;
81 import org.opendaylight.yangtools.yang.common.Uint32;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public class RendererServiceOperationsImpl implements RendererServiceOperations {
88 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
89 "Device rendering was not successful! Rendering will be rolled back.";
90 private static final String OLM_ROLL_BACK_MSG =
91 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
92 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
93 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
94 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
95 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
96 private static final String FAILED = "Failed";
97 private static final String OPERATION_FAILED = "Operation Failed";
98 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
99 private static final int NUMBER_OF_THREADS = 4;
101 private final DeviceRendererService deviceRenderer;
102 private final OtnDeviceRendererService otnDeviceRenderer;
103 private final TransportpceOlmService olmService;
104 private final DataBroker dataBroker;
105 private final NotificationPublishService notificationPublishService;
106 private final PortMapping portMapping;
107 private ListeningExecutorService executor;
109 public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
110 OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
111 DataBroker dataBroker, NotificationPublishService notificationPublishService, PortMapping portMapping) {
112 this.deviceRenderer = deviceRenderer;
113 this.otnDeviceRenderer = otnDeviceRenderer;
114 this.olmService = olmService;
115 this.dataBroker = dataBroker;
116 this.notificationPublishService = notificationPublishService;
117 this.portMapping = portMapping;
118 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
122 public ListenableFuture<ServiceImplementationRequestOutput>
123 serviceImplementation(ServiceImplementationRequestInput input) {
124 LOG.info("Calling service impl request {}", input.getServiceName());
125 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
128 public ServiceImplementationRequestOutput call() throws Exception {
129 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
130 RpcStatusEx.Pending, "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.rev220114.network.Nodes
134 mappingNode = portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
135 ? portMapping.getNode(input.getServiceAEnd().getNodeId())
137 String serviceType = ServiceTypes.getServiceType(
138 input.getServiceAEnd().getServiceFormat().getName(),
141 && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
142 && input.getServiceAEnd().getTxDirection() != null
143 && input.getServiceAEnd().getTxDirection().getPort() != null
144 && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null)
145 ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
146 input.getServiceAEnd().getTxDirection().getPort().getPortName())
149 switch (serviceType) {
150 case StringConstants.SERVICE_TYPE_100GE_T:
151 case StringConstants.SERVICE_TYPE_400GE:
152 case StringConstants.SERVICE_TYPE_OTU4:
153 case StringConstants.SERVICE_TYPE_OTUC2:
154 case StringConstants.SERVICE_TYPE_OTUC3:
155 case StringConstants.SERVICE_TYPE_OTUC4:
156 if (!manageServicePathCreation(input, serviceType)) {
157 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
161 case StringConstants.SERVICE_TYPE_1GE:
162 case StringConstants.SERVICE_TYPE_10GE:
163 case StringConstants.SERVICE_TYPE_100GE_M:
164 case StringConstants.SERVICE_TYPE_100GE_S:
165 case StringConstants.SERVICE_TYPE_ODU4:
166 case StringConstants.SERVICE_TYPE_ODUC2:
167 case StringConstants.SERVICE_TYPE_ODUC3:
168 case StringConstants.SERVICE_TYPE_ODUC4:
169 if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
170 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
175 LOG.error("unsupported service-type");
176 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
179 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
180 OPERATION_SUCCESSFUL);
186 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
187 String serviceName = input.getServiceName();
188 LOG.info("Calling service delete request {}", serviceName);
189 return executor.submit(new Callable<ServiceDeleteOutput>() {
192 public ServiceDeleteOutput call() throws Exception {
193 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
194 RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
195 // Obtain path description
197 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
198 .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
199 if (pathDescriptionOpt.isEmpty()) {
200 LOG.error("Unable to get path description for service {}!", serviceName);
201 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
202 RpcStatusEx.Failed, "Unable to get path description for service");
203 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
206 PathDescription pathDescription = pathDescriptionOpt.get();
207 Mapping mapping = portMapping.getMapping(service.getServiceAEnd().getNodeId().getValue(),
208 service.getServiceAEnd().getTxDirection().getPort().getPortName());
209 String serviceType = ServiceTypes.getServiceType(service.getServiceAEnd().getServiceFormat().getName(),
210 service.getServiceAEnd().getServiceRate(), mapping);
211 switch (serviceType) {
212 case StringConstants.SERVICE_TYPE_100GE_T:
213 case StringConstants.SERVICE_TYPE_400GE:
214 case StringConstants.SERVICE_TYPE_OTU4:
215 case StringConstants.SERVICE_TYPE_OTUC2:
216 case StringConstants.SERVICE_TYPE_OTUC3:
217 case StringConstants.SERVICE_TYPE_OTUC4:
218 if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
219 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
223 case StringConstants.SERVICE_TYPE_1GE:
224 case StringConstants.SERVICE_TYPE_10GE:
225 case StringConstants.SERVICE_TYPE_100GE_M:
226 case StringConstants.SERVICE_TYPE_100GE_S:
227 case StringConstants.SERVICE_TYPE_ODU4:
228 case StringConstants.SERVICE_TYPE_ODUC2:
229 case StringConstants.SERVICE_TYPE_ODUC3:
230 case StringConstants.SERVICE_TYPE_ODUC4:
231 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
232 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
237 LOG.error("unsupported service-type");
238 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
241 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
246 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
247 value = "UPM_UNCALLED_PRIVATE_METHOD",
248 justification = "call in call() method")
249 private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
250 if (input.getServiceAEnd() == null) {
251 LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
254 if (input.getServiceAEnd().getServiceRate() != null) {
255 return input.getServiceAEnd().getServiceRate();
257 LOG.warn("Input should have rate if you are using 200 or 300G");
258 // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
259 Map<ServiceFormat, Map<String, Uint32>> formatRateMap = Map.of(
260 ServiceFormat.OTU, Map.of(
261 "OTUCn", Uint32.valueOf(400),
262 "OTU4", Uint32.valueOf(100),
263 "OTU2", Uint32.valueOf(10),
264 "OTU2e", Uint32.valueOf(10)),
265 ServiceFormat.ODU, Map.of(
266 "ODUCn",Uint32.valueOf(400),
267 "ODU4", Uint32.valueOf(100),
268 "ODU2", Uint32.valueOf(10),
269 "ODU2e", Uint32.valueOf(10),
270 "ODU0", Uint32.valueOf(1)));
271 if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
272 LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
273 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
277 ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
278 ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
279 : input.getServiceAEnd().getOduServiceRate().getSimpleName();
280 if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
281 LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
282 input.getServiceName(), serviceName);
285 return formatRateMap.get(input.getServiceAEnd().getServiceFormat()).get(serviceName);
288 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
289 value = "UPM_UNCALLED_PRIVATE_METHOD",
290 justification = "call in call() method")
291 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
292 throws InterruptedException, ExecutionException, TimeoutException {
293 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
294 Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
295 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
296 return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
299 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
300 value = "UPM_UNCALLED_PRIVATE_METHOD",
301 justification = "call in call() method")
302 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
303 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
304 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
305 .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
306 .child(ServicePaths.class, new ServicePathsKey(serviceName))
307 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
308 .service.path.PathDescription.class);
309 ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
311 LOG.debug("Getting path description for service {}", serviceName);
312 return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
313 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
314 } catch (InterruptedException | ExecutionException | TimeoutException e) {
315 LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
317 return Optional.empty();
321 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
322 value = "UPM_UNCALLED_PRIVATE_METHOD",
323 justification = "call in call() method")
324 private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
325 ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
326 LOG.info(RENDERING_DEVICES_A_Z_MSG);
327 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
328 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
329 RENDERING_DEVICES_A_Z_MSG);
330 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
331 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
332 ServicePathDirection.A_TO_Z));
334 LOG.info("Rendering devices Z-A");
335 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
336 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
337 RENDERING_DEVICES_Z_A_MSG);
338 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
339 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
340 ServicePathDirection.Z_TO_A));
341 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
342 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
344 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
346 LOG.info("Waiting for A-Z and Z-A device renderers ...");
347 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
348 } catch (InterruptedException | ExecutionException | TimeoutException e) {
349 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
350 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
351 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
352 DEVICE_RENDERING_ROLL_BACK_MSG);
353 //FIXME we can't do rollback here, because we don't have rendering results.
354 return renderingResults;
357 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
358 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
359 this.deviceRenderer));
360 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
361 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
362 this.deviceRenderer));
363 return renderingResults;
366 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
367 value = "UPM_UNCALLED_PRIVATE_METHOD",
368 justification = "call in call() method")
369 private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
370 OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA, String serviceType) {
371 LOG.info(RENDERING_DEVICES_A_Z_MSG);
372 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
373 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
374 RENDERING_DEVICES_A_Z_MSG);
375 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
376 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
377 LOG.info(RENDERING_DEVICES_Z_A_MSG);
378 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
379 otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
380 RENDERING_DEVICES_Z_A_MSG);
381 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
382 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
383 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
384 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
385 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
387 LOG.info("Waiting for A-Z and Z-A device renderers ...");
388 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
389 } catch (InterruptedException | ExecutionException | TimeoutException e) {
390 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
391 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
392 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
393 DEVICE_RENDERING_ROLL_BACK_MSG);
394 //FIXME we can't do rollback here, because we don't have rendering results.
395 return otnRenderingResults;
397 for (int i = 0; i < otnRenderingResults.size(); i++) {
398 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("DeviceTask n° " + i + 1,
399 ! otnRenderingResults.get(i).isSuccess(), otnRenderingResults.get(i).getRenderedNodeInterfaces(),
400 this.deviceRenderer));
402 return otnRenderingResults;
405 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
406 value = "UPM_UNCALLED_PRIVATE_METHOD",
407 justification = "call in call() method")
408 private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
409 ServicePowerSetupInput powerSetupInputZtoA) {
410 LOG.info("Olm power setup A-Z");
411 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
412 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
413 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
414 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
416 LOG.info("OLM power setup Z-A");
417 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
418 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
419 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
420 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
421 ListenableFuture<List<OLMRenderingResult>> olmFutures =
422 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
424 List<OLMRenderingResult> olmResults;
426 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
427 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
428 } catch (InterruptedException | ExecutionException | TimeoutException e) {
429 LOG.warn(OLM_ROLL_BACK_MSG, e);
430 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
431 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
433 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
434 this.olmService, powerSetupInputAtoZ));
435 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
436 this.olmService, powerSetupInputZtoA));
440 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
441 this.olmService, powerSetupInputAtoZ));
442 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
443 this.olmService, powerSetupInputZtoA));
446 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
447 value = "UPM_UNCALLED_PRIVATE_METHOD",
448 justification = "call in call() method")
449 private boolean isServiceActivated(String nodeId, String tpId) {
450 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
451 for (int i = 0; i < 3; i++) {
452 List<Measurements> measurements = getMeasurements(nodeId, tpId);
453 if (measurements == null) {
454 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
457 if (verifyPreFecBer(measurements)) {
461 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
462 } catch (InterruptedException ex) {
463 Thread.currentThread().interrupt();
466 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
470 private List<Measurements> getMeasurements(String nodeId, String tp) {
471 GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder()
473 .setGranularity(PmGranularity._15min)
474 .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
475 .setResourceType(ResourceTypeEnum.Interface);
478 Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
479 RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
480 GetPmOutput getPmOutput = getPmRpcResult.getResult();
481 if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
482 LOG.info("successfully finished calling OLM's get PM");
483 return getPmOutput.getMeasurements();
486 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
489 } catch (ExecutionException | InterruptedException e) {
490 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
495 private boolean verifyPreFecBer(List<Measurements> measurements) {
496 double preFecCorrectedErrors = Double.MIN_VALUE;
497 double fecUncorrectableBlocks = Double.MIN_VALUE;
499 for (Measurements measurement : measurements) {
500 switch (measurement.getPmparameterName()) {
501 case "preFECCorrectedErrors":
502 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
504 case "FECUncorrectableBlocks":
505 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
512 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
513 fecUncorrectableBlocks);
515 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
516 LOG.error("Data has uncorrectable errors, BER test failed");
520 double numOfBitsPerSecond = 112000000000d;
521 double threshold = 0.00002d;
522 double result = preFecCorrectedErrors / numOfBitsPerSecond;
523 LOG.info("PreFEC value is {}", Double.toString(result));
524 return result <= threshold;
527 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
528 value = "UPM_UNCALLED_PRIVATE_METHOD",
529 justification = "call in call() method")
530 private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
531 ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
532 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
533 ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
534 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
535 // Rollback should be same for all conditions, so creating a new one
536 RollbackProcessor rollbackProcessor = new RollbackProcessor();
537 List<DeviceRenderingResult> renderingResults =
538 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
539 if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
540 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
541 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
544 ServicePowerSetupInput olmPowerSetupInputAtoZ =
545 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
546 ServicePowerSetupInput olmPowerSetupInputZtoA =
547 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
548 olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
549 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
550 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
551 input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
554 // run service activation test twice - once on source node and once on
556 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
557 if ((nodes == null) || (nodes.isEmpty())) {
561 Nodes sourceNode = nodes.get(0);
562 Nodes destNode = nodes.get(nodes.size() - 1);
563 String srcNetworkTp =
564 sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
565 ? sourceNode.getDestTp()
566 : sourceNode.getSrcTp();
567 String dstNetowrkTp =
568 destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
569 ? destNode.getDestTp()
570 : destNode.getSrcTp();
572 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
573 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
574 rollbackProcessor.rollbackAll();
575 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
576 input.getServiceName(), RpcStatusEx.Failed,
577 "Service activation test failed.");
580 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
581 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
582 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
584 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
585 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
586 notifLink, null, serviceType);
590 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
591 value = "UPM_UNCALLED_PRIVATE_METHOD",
592 justification = "call in call() method")
593 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
594 throws InterruptedException {
595 ServicePathInputData servicePathInputDataAtoZ =
596 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
597 ServicePathInputData servicePathInputDataZtoA =
598 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
599 // OLM turn down power
601 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
602 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
603 RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
604 ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
605 // TODO add some flag rather than string
606 if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
607 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
608 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
609 "Service power turndown failed on A-to-Z path for service");
612 LOG.debug("Turning down power on Z-to-A path");
613 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
614 "Turning down power on Z-to-A path");
615 ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
616 // TODO add some flag rather than string
617 if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
618 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
619 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
620 "Service power turndown failed on Z-to-A path for service");
623 } catch (InterruptedException | ExecutionException | TimeoutException e) {
624 LOG.error("Error while turning down power!", e);
627 // delete service path with renderer
628 LOG.info("Deleting service path via renderer");
629 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
630 "Deleting service path via renderer");
631 RollbackProcessor rollbackProcessor = new RollbackProcessor();
632 List<DeviceRenderingResult> renderingResults =
633 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
634 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
635 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
636 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
638 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
639 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, null, serviceType);
643 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
644 value = "UPM_UNCALLED_PRIVATE_METHOD",
645 justification = "call in call() method")
646 private boolean manageOtnServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
647 Uint32 serviceRate) {
649 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
650 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
651 input.getServiceAEnd().getServiceFormat().getName(),
653 input.getPathDescription(), true);
655 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
656 .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
657 input.getServiceZEnd().getServiceFormat().getName(),
659 input.getPathDescription(), false);
660 // Rollback should be same for all conditions, so creating a new one
661 RollbackProcessor rollbackProcessor = new RollbackProcessor();
662 List<OtnDeviceRenderingResult> renderingResults =
663 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
664 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
665 rollbackProcessor.rollbackAll();
666 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
667 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
670 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
671 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
672 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
673 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription());
674 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
676 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
677 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
678 notifLink, supportedLinks, serviceType);
682 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
683 value = "UPM_UNCALLED_PRIVATE_METHOD",
684 justification = "call in call() method")
685 private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
686 Services service, String serviceType) {
688 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
689 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
690 service.getServiceAEnd().getServiceFormat().getName(),
691 service.getServiceAEnd().getServiceRate(),
692 pathDescription, true);
694 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
695 .rendererCreateOtnServiceInput(serviceName, Action.Delete,
696 service.getServiceZEnd().getServiceFormat().getName(),
697 service.getServiceAEnd().getServiceRate(),
698 pathDescription, false);
699 LOG.info("Deleting otn-service path {} via renderer", serviceName);
700 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
701 "Deleting otn-service path via renderer");
703 RollbackProcessor rollbackProcessor = new RollbackProcessor();
704 List<OtnDeviceRenderingResult> renderingResults =
705 otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
707 List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
708 renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
709 Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
710 List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(pathDescription);
711 List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
713 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
714 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, supportedLinks,
720 * Send renderer notification.
721 * @param servicePathNotificationTypes ServicePathNotificationTypes
722 * @param serviceName String
723 * @param rpcStatusEx RpcStatusEx
724 * @param message String
726 private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
727 RpcStatusEx rpcStatusEx, String message) {
728 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
729 null, null, null, null);
734 * Send renderer notification with path description information.
735 * @param servicePathNotificationTypes ServicePathNotificationTypes
736 * @param serviceName String
737 * @param rpcStatusEx RpcStatusEx
738 * @param message String
739 * @param pathDescription PathDescription
741 private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
742 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
743 Link notifLink, List<String> supportedLinks, String serviceType) {
744 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
745 pathDescription, notifLink, supportedLinks, serviceType);
750 * Build notification containing path description information.
751 * @param servicePathNotificationTypes ServicePathNotificationTypes
752 * @param serviceName String
753 * @param rpcStatusEx RpcStatusEx
754 * @param message String
755 * @param pathDescription PathDescription
756 * @return notification with RendererRpcResultSp type.
758 private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
759 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
760 Link notifLink, List<String> supportedLinks, String serviceType) {
761 RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
762 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
763 .setStatusMessage(message)
764 .setServiceType(serviceType);
765 if (pathDescription != null) {
766 builder.setAToZDirection(pathDescription.getAToZDirection())
767 .setZToADirection(pathDescription.getZToADirection());
769 if (notifLink != null) {
770 builder.setLink(notifLink);
772 if (supportedLinks != null) {
773 builder.setLinkId(supportedLinks);
775 return builder.build();
779 * Send renderer notification.
780 * @param notification Notification
782 private void send(Notification notification) {
784 LOG.info("Sending notification {}", notification);
785 notificationPublishService.putNotification(notification);
786 } catch (InterruptedException e) {
787 LOG.info("notification offer rejected: ", e);
788 Thread.currentThread().interrupt();
792 private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
793 if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
796 return new LinkBuilder()
797 .setATermination(new ATerminationBuilder()
798 .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
799 .setTpId(otnLinkTerminationPoints.get(0).getTpId())
801 .setZTermination(new ZTerminationBuilder()
802 .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
803 .setTpId(otnLinkTerminationPoints.get(1).getTpId())
808 private List<String> getSupportedLinks(List<String> allSupportLinks, String serviceType) {
809 switch (serviceType) {
810 case StringConstants.SERVICE_TYPE_10GE:
811 case StringConstants.SERVICE_TYPE_1GE:
812 return allSupportLinks.stream()
813 .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toList());
814 case StringConstants.SERVICE_TYPE_100GE_M:
815 return allSupportLinks.stream()
816 .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toList());
817 case StringConstants.SERVICE_TYPE_ODU4:
818 case StringConstants.SERVICE_TYPE_100GE_S:
819 return allSupportLinks.stream()
820 .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
821 case StringConstants.SERVICE_TYPE_ODUC4:
822 return allSupportLinks.stream()
823 .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());