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;
16 import java.util.Optional;
17 import java.util.concurrent.Callable;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Executors;
20 import java.util.concurrent.Future;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
25 import org.opendaylight.mdsal.binding.api.ReadTransaction;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.transportpce.common.ResponseCodes;
28 import org.opendaylight.transportpce.common.StringConstants;
29 import org.opendaylight.transportpce.common.Timeouts;
30 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
31 import org.opendaylight.transportpce.renderer.ServicePathInputData;
32 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
33 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
34 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
35 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
36 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev200128.OtnServicePathInput;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev200128.OtnServicePathOutput;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmInputBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmOutput;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerSetupInput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownInputBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownOutput;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.get.pm.output.Measurements;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.RendererRpcResultSp;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.RendererRpcResultSpBuilder;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceDeleteInput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceDeleteOutput;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestInput;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestOutput;
54 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.ODU4;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.ODUCn;
57 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.OTU4;
58 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.OTUCn;
59 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
60 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
61 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
62 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
63 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev201210.PathDescription;
64 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
65 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.ServicePathNotificationTypes;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev201211.olm.get.pm.input.ResourceIdentifierBuilder;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev201211.olm.renderer.input.Nodes;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
72 import org.opendaylight.yangtools.yang.binding.Notification;
73 import org.opendaylight.yangtools.yang.common.RpcResult;
74 import org.opendaylight.yangtools.yang.common.Uint32;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
79 public class RendererServiceOperationsImpl implements RendererServiceOperations {
81 private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
82 "Device rendering was not successful! Rendering will be rolled back.";
83 private static final String OLM_ROLL_BACK_MSG =
84 "OLM power setup was not successful! Rendering and OLM will be rolled back.";
85 private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
86 private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
87 private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
88 private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
89 private static final String FAILED = "Failed";
90 private static final String OPERATION_FAILED = "Operation Failed";
91 private static final String OPERATION_SUCCESSFUL = "Operation Successful";
92 private static final int NUMBER_OF_THREADS = 4;
94 private final DeviceRendererService deviceRenderer;
95 private final OtnDeviceRendererService otnDeviceRenderer;
96 private final TransportpceOlmService olmService;
97 private final DataBroker dataBroker;
98 private final NotificationPublishService notificationPublishService;
99 private ListeningExecutorService executor;
101 public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
102 OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
103 DataBroker dataBroker, NotificationPublishService notificationPublishService) {
104 this.deviceRenderer = deviceRenderer;
105 this.otnDeviceRenderer = otnDeviceRenderer;
106 this.olmService = olmService;
107 this.dataBroker = dataBroker;
108 this.notificationPublishService = notificationPublishService;
109 this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
113 public ListenableFuture<ServiceImplementationRequestOutput>
114 serviceImplementation(ServiceImplementationRequestInput input) {
115 LOG.info("Calling service impl request {}", input.getServiceName());
116 return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
119 public ServiceImplementationRequestOutput call() throws Exception {
120 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
121 RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
122 // Here is the switch statement that distinguishes on the connection-type
123 LOG.info("Connection-type is {} for {}", input.getConnectionType(), input.getServiceName());
124 switch (input.getConnectionType()) {
125 case Service: case RoadmLine: // This takes into account of Ethernet 100G, 1G, 10G and ODU4
126 LOG.info("RPC implementation for {}", input.getConnectionType());
127 if (((input.getServiceAEnd().getServiceRate() != null)
128 && ((input.getServiceAEnd().getServiceRate().intValue() == 100))
129 || (input.getServiceAEnd().getServiceRate().intValue() == 400))
130 && ((input.getServiceAEnd().getServiceFormat().getName().equals("Ethernet"))
131 || (input.getServiceAEnd().getServiceFormat().getName().equals("OC")))) {
132 LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
133 input.getServiceAEnd().getServiceFormat(), input.getServiceAEnd().getServiceRate());
134 if (!createServicepathInput(input)) {
135 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
138 } else { // This implies, service-rate is 1 or 10G
139 // This includes the lower-order odu (1G, 10G, 100G) and this is A-Z side
140 LOG.info("RPC implementation for LO-ODU");
141 String serviceRate = ""; // Assuming service at A-side and Z-side has same service rate
142 if (input.getServiceAEnd().getServiceRate() != null) {
143 serviceRate = input.getServiceAEnd().getServiceRate().toString() + "G";
145 LOG.info("Start rendering for {} service with {} rate and {} format",
146 input.getServiceName(), serviceRate,
147 input.getServiceAEnd().getServiceFormat());
149 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
150 .rendererCreateOtnServiceInput(input.getServiceName(),
151 input.getServiceAEnd().getServiceFormat().getName(),
152 serviceRate, (PathDescription) input.getPathDescription(), true);
153 // Rollback should be same for all conditions, so creating a new one
154 RollbackProcessor rollbackProcessor = new RollbackProcessor();
155 List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
156 otnServicePathInputAtoZ, null);
157 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
158 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
159 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
160 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
163 LOG.info("OTN rendering result size {}", otnRenderingResults.size());
167 LOG.info("RPC implementation for {}", input.getConnectionType());
168 if (input.getServiceAEnd().getOtuServiceRate() != null) {
169 if ((input.getServiceAEnd().getOtuServiceRate().equals(OTU4.class))
170 || (input.getServiceAEnd().getOtuServiceRate().equals(OTUCn.class))) {
171 // For the service of OTU4 or OTUCn infrastructure
172 // Create the OCH and OTU interfaces for OTU4 class
173 // Create OTSi, OTSi-group and OTUCn interface
174 if (!createServicepathInput(input)) {
175 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
180 if (input.getServiceAEnd().getOduServiceRate() != null) {
181 String serviceRate = null;
182 if (input.getServiceAEnd().getOduServiceRate().equals(ODU4.class)) {
183 // For the service of OTU4 infrastructure
184 serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
186 else if (input.getServiceAEnd().getOduServiceRate().equals(ODUCn.class)) {
187 // For the service of OTUCn infrastructure
188 // TODO: what happens if split-lambda where to be used? We will have ODUC2 rate,
189 // TODO: which case service-rate would be 200
190 // TODO: in that case it would be 200G?? Need to understand more
191 serviceRate = "400G"; // For OtnDeviceRendererServiceImpl
193 LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
194 input.getServiceAEnd().getOduServiceRate(), serviceRate);
195 // Now start rendering ODU4 or ODUC4 interface
197 OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
198 .rendererCreateOtnServiceInput(input.getServiceName(),
199 input.getServiceAEnd().getServiceFormat().getName(),
201 input.getPathDescription(), true);
203 OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
204 .rendererCreateOtnServiceInput(input.getServiceName(),
205 input.getServiceZEnd().getServiceFormat().getName(),
207 input.getPathDescription(), false);
208 // Rollback should be same for all conditions, so creating a new one
209 RollbackProcessor rollbackProcessor = new RollbackProcessor();
210 List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
211 otnServicePathInputAtoZ, otnServicePathInputZtoA);
212 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
213 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
214 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
215 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
218 LOG.info("OTN rendering result size {}", otnRenderingResults.size());
222 LOG.warn("Unsupported connection type {}", input.getConnectionType());
224 sendNotificationsWithPathDescription(
225 ServicePathNotificationTypes.ServiceImplementationRequest,
226 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
227 input.getPathDescription());
228 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
229 OPERATION_SUCCESSFUL);
235 public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
236 String serviceName = input.getServiceName();
237 LOG.info("Calling service delete request {}", serviceName);
238 return executor.submit(new Callable<ServiceDeleteOutput>() {
241 public ServiceDeleteOutput call() throws Exception {
242 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
243 RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
244 // Obtain path description
246 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
247 .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
248 PathDescription pathDescription;
249 if (pathDescriptionOpt.isPresent()) {
250 pathDescription = pathDescriptionOpt.get();
252 LOG.error("Unable to get path description for service {}!", serviceName);
253 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
254 RpcStatusEx.Failed, "Unable to get path description for service");
255 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
258 switch (service.getConnectionType()) {
261 if ((ServiceFormat.Ethernet.equals(service.getServiceAEnd().getServiceFormat())
262 || ServiceFormat.OC.equals(service.getServiceAEnd().getServiceFormat()))
263 && Uint32.valueOf("100").equals(service.getServiceAEnd().getServiceRate())) {
264 if (!manageServicePathDeletion(serviceName, pathDescription)) {
265 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
269 if (ServiceFormat.Ethernet.equals(service.getServiceAEnd().getServiceFormat())
270 && (Uint32.valueOf("10").equals(service.getServiceAEnd().getServiceRate())
271 || Uint32.valueOf("1").equals(service.getServiceAEnd().getServiceRate()))) {
272 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service)) {
273 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
279 if (ServiceFormat.OTU.equals(service.getServiceAEnd().getServiceFormat())) {
280 if (!manageServicePathDeletion(serviceName, pathDescription)) {
281 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
284 } else if (ServiceFormat.ODU.equals(service.getServiceAEnd().getServiceFormat())) {
285 if (!manageOtnServicePathDeletion(serviceName, pathDescription, service)) {
286 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
292 LOG.error("Unmanaged connection-type for deletion of service {}", serviceName);
295 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
300 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
301 value = "UPM_UNCALLED_PRIVATE_METHOD",
302 justification = "call in call() method")
303 private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
304 throws InterruptedException, ExecutionException, TimeoutException {
305 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
306 Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
307 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
308 return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
311 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
312 value = "UPM_UNCALLED_PRIVATE_METHOD",
313 justification = "call in call() method")
314 private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
315 .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
316 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
317 .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
318 .child(ServicePaths.class, new ServicePathsKey(serviceName))
319 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
320 .service.path.PathDescription.class);
321 ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
323 LOG.debug("Getting path description for service {}", serviceName);
324 return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
325 .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
326 } catch (InterruptedException | ExecutionException | TimeoutException e) {
327 LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
329 return Optional.empty();
333 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
334 value = "UPM_UNCALLED_PRIVATE_METHOD",
335 justification = "call in call() method")
336 private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
337 ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
338 LOG.info(RENDERING_DEVICES_A_Z_MSG);
339 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
340 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
341 RENDERING_DEVICES_A_Z_MSG);
342 ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
343 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
344 ServicePathDirection.A_TO_Z));
346 LOG.info("Rendering devices Z-A");
347 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
348 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
349 RENDERING_DEVICES_Z_A_MSG);
350 ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
351 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
352 ServicePathDirection.Z_TO_A));
353 ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
354 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
356 List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
358 LOG.info("Waiting for A-Z and Z-A device renderers ...");
359 renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
360 } catch (InterruptedException | ExecutionException | TimeoutException e) {
361 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
362 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
363 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
364 DEVICE_RENDERING_ROLL_BACK_MSG);
365 //FIXME we can't do rollback here, because we don't have rendering results.
366 return renderingResults;
369 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
370 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
371 this.deviceRenderer));
372 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
373 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
374 this.deviceRenderer));
375 return renderingResults;
378 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
379 value = "UPM_UNCALLED_PRIVATE_METHOD",
380 justification = "call in call() method")
381 private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
382 OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA) {
383 LOG.info(RENDERING_DEVICES_A_Z_MSG);
384 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
385 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
386 RENDERING_DEVICES_A_Z_MSG);
387 ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
388 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ));
389 ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture;
390 if (otnServicePathZtoA != null) {
391 LOG.info("Rendering devices Z-A");
392 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
393 otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
394 RENDERING_DEVICES_Z_A_MSG);
395 ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
396 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
397 renderingCombinedFuture = Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
399 renderingCombinedFuture = Futures.allAsList(atozrenderingFuture);
401 List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
403 LOG.info("Waiting for A-Z and Z-A device renderers ...");
404 otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
405 } catch (InterruptedException | ExecutionException | TimeoutException e) {
406 LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
407 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
408 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
409 DEVICE_RENDERING_ROLL_BACK_MSG);
410 //FIXME we can't do rollback here, because we don't have rendering results.
411 return otnRenderingResults;
413 for (int i = 0; i < otnRenderingResults.size(); i++) {
414 rollbackProcessor.addTask(new DeviceRenderingRollbackTask("DeviceTask n° " + i + 1,
415 ! otnRenderingResults.get(i).isSuccess(), otnRenderingResults.get(i).getRenderedNodeInterfaces(),
416 this.deviceRenderer));
418 return otnRenderingResults;
421 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
422 value = "UPM_UNCALLED_PRIVATE_METHOD",
423 justification = "call in call() method")
424 private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
425 ServicePowerSetupInput powerSetupInputZtoA) {
426 LOG.info("Olm power setup A-Z");
427 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
428 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
429 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
430 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
432 LOG.info("OLM power setup Z-A");
433 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
434 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
435 ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
436 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
437 ListenableFuture<List<OLMRenderingResult>> olmFutures =
438 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
440 List<OLMRenderingResult> olmResults;
442 LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
443 olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
444 } catch (InterruptedException | ExecutionException | TimeoutException e) {
445 LOG.warn(OLM_ROLL_BACK_MSG, e);
446 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
447 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
449 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
450 this.olmService, powerSetupInputAtoZ));
451 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
452 this.olmService, powerSetupInputZtoA));
456 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
457 this.olmService, powerSetupInputAtoZ));
458 rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
459 this.olmService, powerSetupInputZtoA));
462 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
463 value = "UPM_UNCALLED_PRIVATE_METHOD",
464 justification = "call in call() method")
465 private boolean isServiceActivated(String nodeId, String tpId) {
466 LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
467 for (int i = 0; i < 3; i++) {
468 List<Measurements> measurements = getMeasurements(nodeId, tpId);
469 if ((measurements != null) && verifyPreFecBer(measurements)) {
471 } else if (measurements == null) {
472 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
476 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
477 } catch (InterruptedException ex) {
478 Thread.currentThread().interrupt();
482 LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
486 private List<Measurements> getMeasurements(String nodeId, String tp) {
487 GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder();
488 getPmIpBldr.setNodeId(nodeId);
489 getPmIpBldr.setGranularity(PmGranularity._15min);
490 ResourceIdentifierBuilder rsrcBldr = new ResourceIdentifierBuilder();
491 rsrcBldr.setResourceName(tp + "-OTU");
492 getPmIpBldr.setResourceIdentifier(rsrcBldr.build());
493 getPmIpBldr.setResourceType(ResourceTypeEnum.Interface);
496 Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
497 RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
498 GetPmOutput getPmOutput = getPmRpcResult.getResult();
499 if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
500 LOG.info("successfully finished calling OLM's get PM");
501 return getPmOutput.getMeasurements();
504 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
507 } catch (ExecutionException | InterruptedException e) {
508 LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
513 private boolean verifyPreFecBer(List<Measurements> measurements) {
514 double preFecCorrectedErrors = Double.MIN_VALUE;
515 double fecUncorrectableBlocks = Double.MIN_VALUE;
517 for (Measurements measurement : measurements) {
518 if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
519 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
521 if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
522 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
526 LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
527 fecUncorrectableBlocks);
529 if (fecUncorrectableBlocks > Double.MIN_VALUE) {
530 LOG.error("Data has uncorrectable errors, BER test failed");
533 double numOfBitsPerSecond = 112000000000d;
534 double threshold = 0.00002d;
535 double result = preFecCorrectedErrors / numOfBitsPerSecond;
536 LOG.info("PreFEC value is {}", Double.toString(result));
537 return result <= threshold;
541 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
542 value = "UPM_UNCALLED_PRIVATE_METHOD",
543 justification = "call in call() method")
544 private boolean createServicepathInput(ServiceImplementationRequestInput input) {
545 ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
546 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
547 ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
548 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
549 // Rollback should be same for all conditions, so creating a new one
550 RollbackProcessor rollbackProcessor = new RollbackProcessor();
551 List<DeviceRenderingResult> renderingResults =
552 deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
553 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
554 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
555 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
558 ServicePowerSetupInput olmPowerSetupInputAtoZ =
559 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
560 ServicePowerSetupInput olmPowerSetupInputZtoA =
561 ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
562 olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
563 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
564 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
565 input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
568 // run service activation test twice - once on source node and once on
570 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
571 if ((nodes == null) || (nodes.isEmpty())) {
575 Nodes sourceNode = nodes.get(0);
576 Nodes destNode = nodes.get(nodes.size() - 1);
579 if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
580 srcNetworkTp = sourceNode.getDestTp();
582 srcNetworkTp = sourceNode.getSrcTp();
584 if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
585 dstNetowrkTp = destNode.getDestTp();
587 dstNetowrkTp = destNode.getSrcTp();
589 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
590 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
591 rollbackProcessor.rollbackAll();
592 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
593 input.getServiceName(), RpcStatusEx.Failed,
594 "Service activation test failed.");
597 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
598 input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription());
602 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
603 value = "UPM_UNCALLED_PRIVATE_METHOD",
604 justification = "call in call() method")
605 private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription) {
606 ServicePathInputData servicePathInputDataAtoZ =
607 ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription);
608 ServicePathInputData servicePathInputDataZtoA =
609 ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription);
610 // OLM turn down power
612 LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
613 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
614 RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
615 ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
616 // TODO add some flag rather than string
617 if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
618 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
619 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
620 "Service power turndown failed on A-to-Z path for service");
623 LOG.debug("Turning down power on Z-to-A path");
624 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
625 "Turning down power on Z-to-A path");
626 ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
627 // TODO add some flag rather than string
628 if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
629 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
630 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
631 "Service power turndown failed on Z-to-A path for service");
634 } catch (InterruptedException | ExecutionException | TimeoutException e) {
635 LOG.error("Error while turning down power!", e);
638 // delete service path with renderer
639 LOG.info("Deleting service path via renderer");
640 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
641 "Deleting service path via renderer");
642 deviceRenderer.deleteServicePath(servicePathInputDataAtoZ.getServicePathInput());
643 deviceRenderer.deleteServicePath(servicePathInputDataZtoA.getServicePathInput());
644 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
645 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL,pathDescription);
649 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
650 value = "UPM_UNCALLED_PRIVATE_METHOD",
651 justification = "call in call() method")
652 private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
654 OtnServicePathInput ospi = null;
655 if (ConnectionType.Infrastructure.equals(service.getConnectionType())) {
656 ospi = ModelMappingUtils.rendererCreateOtnServiceInput(
657 serviceName, service.getServiceAEnd().getServiceFormat().getName(), "100G", pathDescription, true);
658 } else if (ConnectionType.Service.equals(service.getConnectionType())) {
659 ospi = ModelMappingUtils.rendererCreateOtnServiceInput(serviceName,
660 service.getServiceAEnd().getServiceFormat().getName(),
661 service.getServiceAEnd().getServiceRate().toString() + "G", pathDescription, true);
663 LOG.info("Deleting otn-service path {} via renderer", serviceName);
664 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
665 "Deleting otn-service path via renderer");
666 OtnServicePathOutput result = otnDeviceRenderer.deleteOtnServicePath(ospi);
667 if (result.getSuccess()) {
668 sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
669 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription);
677 * Send renderer notification.
678 * @param servicePathNotificationTypes ServicePathNotificationTypes
679 * @param serviceName String
680 * @param rpcStatusEx RpcStatusEx
681 * @param message String
683 private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
684 RpcStatusEx rpcStatusEx, String message) {
685 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
691 * Send renderer notification with path description information.
692 * @param servicePathNotificationTypes ServicePathNotificationTypes
693 * @param serviceName String
694 * @param rpcStatusEx RpcStatusEx
695 * @param message String
696 * @param pathDescription PathDescription
698 private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
699 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription) {
700 Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
706 * Build notification containing path description information.
707 * @param servicePathNotificationTypes ServicePathNotificationTypes
708 * @param serviceName String
709 * @param rpcStatusEx RpcStatusEx
710 * @param message String
711 * @param pathDescription PathDescription
712 * @return notification with RendererRpcResultSp type.
714 private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
715 String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription) {
716 RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
717 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
718 .setStatusMessage(message);
719 if (pathDescription != null) {
720 builder.setAToZDirection(pathDescription.getAToZDirection())
721 .setZToADirection(pathDescription.getZToADirection());
723 return builder.build();
727 * Send renderer notification.
728 * @param notification Notification
730 private void send(Notification notification) {
732 LOG.info("Sending notification {}", notification);
733 notificationPublishService.putNotification(notification);
734 } catch (InterruptedException e) {
735 LOG.info("notification offer rejected: ", e);
736 Thread.currentThread().interrupt();