2ea5077a6be795d34f43843a66cf6865dd94abde
[transportpce.git] / servicehandler / src / main / java / org / opendaylight / transportpce / servicehandler / service / PCEServiceWrapper.java
1 /*
2  * Copyright © 2017 Orange, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.transportpce.servicehandler.service;
9
10 import com.google.common.util.concurrent.FutureCallback;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.ListeningExecutorService;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.Executors;
17 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
18 import org.opendaylight.transportpce.common.ResponseCodes;
19 import org.opendaylight.transportpce.pce.service.PathComputationService;
20 import org.opendaylight.transportpce.servicehandler.ModelMappingUtils;
21 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.CancelResourceReserveInput;
22 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.CancelResourceReserveInputBuilder;
23 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.CancelResourceReserveOutput;
24 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.CancelResourceReserveOutputBuilder;
25 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestInput;
26 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestInputBuilder;
27 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestOutput;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestOutputBuilder;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRerouteRequestInput;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRerouteRequestInputBuilder;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRerouteRequestOutput;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRerouteRequestOutputBuilder;
33 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.path.computation.reroute.request.input.Endpoints;
34 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.path.computation.reroute.request.input.EndpointsBuilder;
35 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.servicehandler.rev201125.ServiceRpcResultSh;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.servicehandler.rev201125.ServiceRpcResultShBuilder;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.ServiceEndpoint;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.ServiceNotificationTypes;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.configuration.response.common.ConfigurationResponseCommon;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.configuration.response.common.ConfigurationResponseCommonBuilder;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.sdnc.request.header.SdncRequestHeader;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev221209.routing.constraints.HardConstraints;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev221209.routing.constraints.SoftConstraints;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceCreateInput;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceFeasibilityCheckInput;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.TempServiceCreateInput;
47 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.PceMetric;
48 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
49 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParameters;
50 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParametersBuilder;
51 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.handler.header.ServiceHandlerHeaderBuilder;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 public class PCEServiceWrapper {
56
57     private static final String NOTIFICATION_OFFER_REJECTED_MSG = "notification offer rejected : ";
58
59     private static final String PERFORMING_PCE_MSG = "performing PCE ...";
60
61     private static final Logger LOG = LoggerFactory.getLogger(PCEServiceWrapper.class);
62
63     private final PathComputationService pathComputationService;
64     private final NotificationPublishService notificationPublishService;
65     private ServiceRpcResultSh notification = null;
66     private final ListeningExecutorService executor;
67
68     public PCEServiceWrapper(PathComputationService pathComputationService,
69             NotificationPublishService notificationPublishService) {
70         this.pathComputationService = pathComputationService;
71         this.notificationPublishService = notificationPublishService;
72         executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
73     }
74
75     public PathComputationRequestOutput performPCE(ServiceCreateInput serviceCreateInput, boolean reserveResource) {
76         LOG.info(PERFORMING_PCE_MSG);
77         if (validateParams(serviceCreateInput.getServiceName(), serviceCreateInput.getSdncRequestHeader())) {
78             return performPCE(serviceCreateInput.getHardConstraints(), serviceCreateInput.getSoftConstraints(),
79                     serviceCreateInput.getServiceName(), serviceCreateInput.getSdncRequestHeader(),
80                     serviceCreateInput.getServiceAEnd(), serviceCreateInput.getServiceZEnd(),
81                     ServiceNotificationTypes.ServiceCreateResult, reserveResource);
82         } else {
83             return returnPCEFailed();
84         }
85     }
86
87     public PathComputationRequestOutput performPCE(TempServiceCreateInput tempServiceCreateInput,
88             boolean reserveResource) {
89         LOG.info(PERFORMING_PCE_MSG);
90         if (validateParams(tempServiceCreateInput.getCommonId(), tempServiceCreateInput.getSdncRequestHeader())) {
91             return performPCE(tempServiceCreateInput.getHardConstraints(), tempServiceCreateInput.getSoftConstraints(),
92                     tempServiceCreateInput.getCommonId(), tempServiceCreateInput.getSdncRequestHeader(),
93                     tempServiceCreateInput.getServiceAEnd(), tempServiceCreateInput.getServiceZEnd(),
94                     ServiceNotificationTypes.ServiceCreateResult, reserveResource);
95         } else {
96             return returnPCEFailed();
97         }
98     }
99
100     public PathComputationRequestOutput performPCE(ServiceFeasibilityCheckInput serviceFeasibilityCheckInput,
101             boolean reserveResource) {
102         LOG.info(PERFORMING_PCE_MSG);
103         if (validateParams(serviceFeasibilityCheckInput.getCommonId(),
104                 serviceFeasibilityCheckInput.getSdncRequestHeader())) {
105             return performPCE(serviceFeasibilityCheckInput.getHardConstraints(),
106                     serviceFeasibilityCheckInput.getSoftConstraints(), serviceFeasibilityCheckInput.getCommonId(),
107                     serviceFeasibilityCheckInput.getSdncRequestHeader(), serviceFeasibilityCheckInput.getServiceAEnd(),
108                     serviceFeasibilityCheckInput.getServiceZEnd(),
109                     ServiceNotificationTypes.ServiceCreateResult, reserveResource);
110         } else {
111             return returnPCEFailed();
112         }
113     }
114
115     private PathComputationRequestOutput performPCE(HardConstraints hardConstraints, SoftConstraints softConstraints,
116             String serviceName, SdncRequestHeader sdncRequestHeader, ServiceEndpoint serviceAEnd,
117             ServiceEndpoint serviceZEnd, ServiceNotificationTypes notifType, boolean reserveResource) {
118         LOG.info("Calling path computation.");
119         notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName(serviceName)
120                 .setStatus(RpcStatusEx.Pending)
121                 .setStatusMessage("Service compliant, submitting PathComputation Request ...").build();
122         try {
123             notificationPublishService.putNotification(notification);
124         } catch (InterruptedException e) {
125             LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
126         }
127         FutureCallback<PathComputationRequestOutput> pceCallback =
128                 new PathComputationRequestOutputCallback(notifType, serviceName);
129         PathComputationRequestInput pathComputationRequestInput = createPceRequestInput(serviceName, sdncRequestHeader,
130                 hardConstraints, softConstraints, reserveResource, serviceAEnd, serviceZEnd);
131         ListenableFuture<PathComputationRequestOutput> pce = this.pathComputationService
132                 .pathComputationRequest(pathComputationRequestInput);
133         Futures.addCallback(pce, pceCallback, executor);
134
135         ConfigurationResponseCommon configurationResponseCommon = new ConfigurationResponseCommonBuilder()
136                 .setAckFinalIndicator(ResponseCodes.FINAL_ACK_NO)
137                 .setRequestId(sdncRequestHeader.getRequestId())
138                 .setResponseCode(ResponseCodes.RESPONSE_OK)
139                 .setResponseMessage("PCE calculation in progress")
140                 .build();
141         ResponseParameters reponseParameters = new ResponseParametersBuilder().build();
142         return new PathComputationRequestOutputBuilder()
143                 .setConfigurationResponseCommon(configurationResponseCommon)
144                 .setResponseParameters(reponseParameters)
145                 .build();
146     }
147
148     public PathComputationRerouteRequestOutput performPCEReroute(HardConstraints hardConstraints,
149            SoftConstraints softConstraints, SdncRequestHeader serviceHandler, ServiceEndpoint serviceAEnd,
150            ServiceEndpoint serviceZEnd,
151            Endpoints endpoints) {
152         // TODO: Make it asynchronous
153         LOG.info("Calling path computation reroute");
154         PathComputationRerouteRequestInput inputPCE = createPceRerouteRequestInput(hardConstraints, softConstraints,
155                 serviceHandler, serviceAEnd, serviceZEnd, endpoints);
156         ListenableFuture<PathComputationRerouteRequestOutput> res =
157                 pathComputationService.pathComputationRerouteRequest(inputPCE);
158         try {
159             return res.get();
160         } catch (ExecutionException | InterruptedException e) {
161             LOG.warn("PerformPCEReroute FAILED ! ", e);
162             return new PathComputationRerouteRequestOutputBuilder()
163                     .setConfigurationResponseCommon(new ConfigurationResponseCommonBuilder()
164                             .setAckFinalIndicator(ResponseCodes.FINAL_ACK_YES)
165                             .setRequestId("None")
166                             .setResponseCode(ResponseCodes.RESPONSE_OK)
167                             .setResponseMessage("PCE calculation FAILED")
168                             .build())
169                     .build();
170         }
171     }
172
173     private PathComputationRequestInput createPceRequestInput(String serviceName,
174             SdncRequestHeader serviceHandler, HardConstraints hardConstraints,
175             SoftConstraints softConstraints, Boolean reserveResource, ServiceEndpoint serviceAEnd,
176             ServiceEndpoint serviceZEnd) {
177         LOG.info("Mapping ServiceCreateInput or ServiceFeasibilityCheckInput or serviceReconfigureInput to PCE"
178                 + "requests");
179         ServiceHandlerHeaderBuilder serviceHandlerHeader = new ServiceHandlerHeaderBuilder();
180         if (serviceHandler != null) {
181             serviceHandlerHeader.setRequestId(serviceHandler.getRequestId());
182         }
183         return new PathComputationRequestInputBuilder()
184             .setServiceName(serviceName)
185             .setResourceReserve(reserveResource)
186             .setServiceHandlerHeader(serviceHandlerHeader.build())
187             .setHardConstraints(hardConstraints)
188             .setSoftConstraints(softConstraints)
189             .setPceRoutingMetric(PceMetric.TEMetric)
190             .setServiceAEnd(ModelMappingUtils.createServiceAEnd(serviceAEnd))
191             .setServiceZEnd(ModelMappingUtils.createServiceZEnd(serviceZEnd))
192             .build();
193     }
194
195     private PathComputationRerouteRequestInput createPceRerouteRequestInput(HardConstraints hardConstraints,
196             SoftConstraints softConstraints, SdncRequestHeader serviceHandler, ServiceEndpoint serviceAEnd,
197             ServiceEndpoint serviceZEnd, Endpoints endpoints) {
198         LOG.info("Mapping Service-reroute to PCE requests");
199         return new PathComputationRerouteRequestInputBuilder()
200                 .setServiceHandlerHeader(serviceHandler == null
201                         ? new ServiceHandlerHeaderBuilder().build()
202                         : new ServiceHandlerHeaderBuilder().setRequestId(serviceHandler.getRequestId()).build())
203                 .setHardConstraints(hardConstraints)
204                 .setSoftConstraints(softConstraints)
205                 .setPceRoutingMetric(PceMetric.TEMetric)
206                 .setEndpoints(new EndpointsBuilder()
207                         .setAEndTp(endpoints.getAEndTp())
208                         .setZEndTp(endpoints.getZEndTp())
209                         .build())
210                 .setServiceAEnd(ModelMappingUtils.createServiceAEndReroute(serviceAEnd))
211                 .setServiceZEnd(ModelMappingUtils.createServiceZEndReroute(serviceZEnd))
212                 .build();
213     }
214
215     private CancelResourceReserveInput mappingCancelResourceReserve(String serviceName,
216                                                                     SdncRequestHeader sdncRequestHeader) {
217         LOG.info("Mapping to PCE Cancel resource request input");
218         CancelResourceReserveInputBuilder cancelResourceReserveInput = new CancelResourceReserveInputBuilder();
219         if (serviceName != null) {
220             ServiceHandlerHeaderBuilder serviceHandlerHeader = new ServiceHandlerHeaderBuilder();
221             if (sdncRequestHeader != null) {
222                 serviceHandlerHeader.setRequestId(sdncRequestHeader.getRequestId());
223             }
224             cancelResourceReserveInput.setServiceName(serviceName)
225                     .setServiceHandlerHeader(serviceHandlerHeader.build());
226             return cancelResourceReserveInput.build();
227         } else {
228             LOG.error("Service Name (common-id for Temp service) is not set");
229             return null;
230         }
231     }
232
233     public CancelResourceReserveOutput cancelPCEResource(String serviceName, ServiceNotificationTypes notifType) {
234         LOG.info("Calling cancel resource reserve computation.");
235         notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName(serviceName)
236                 .setStatus(RpcStatusEx.Pending)
237                 .setStatusMessage("submitting Cancel resource reserve Request ...").build();
238         try {
239             notificationPublishService.putNotification(notification);
240         } catch (InterruptedException e) {
241             LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
242         }
243         FutureCallback<CancelResourceReserveOutput> pceCallback =
244                 new CancelResourceReserveOutputFutureCallback(notifType, serviceName);
245         CancelResourceReserveInput cancelResourceReserveInput = mappingCancelResourceReserve(serviceName, null);
246         ConfigurationResponseCommonBuilder configurationResponseCommon = new ConfigurationResponseCommonBuilder();
247         if (cancelResourceReserveInput != null) {
248             String requestId = cancelResourceReserveInput.getServiceHandlerHeader().getRequestId();
249             ListenableFuture<CancelResourceReserveOutput> pce =
250                     this.pathComputationService.cancelResourceReserve(cancelResourceReserveInput);
251             Futures.addCallback(pce, pceCallback, executor);
252             if (requestId != null) {
253                 configurationResponseCommon.setRequestId(requestId);
254             }
255             configurationResponseCommon.setAckFinalIndicator(ResponseCodes.FINAL_ACK_NO)
256                     .setResponseCode(ResponseCodes.RESPONSE_OK).setResponseMessage("PCE calculation in progress");
257             return new CancelResourceReserveOutputBuilder()
258                     .setConfigurationResponseCommon(configurationResponseCommon.build()).build();
259         } else {
260             configurationResponseCommon.setAckFinalIndicator(ResponseCodes.FINAL_ACK_YES)
261                     .setResponseCode(ResponseCodes.RESPONSE_FAILED).setResponseMessage("PCE failed !");
262             return new CancelResourceReserveOutputBuilder()
263                     .setConfigurationResponseCommon(configurationResponseCommon.build()).build();
264         }
265     }
266
267     private static PathComputationRequestOutput returnPCEFailed() {
268         ConfigurationResponseCommon configurationResponseCommon = new ConfigurationResponseCommonBuilder()
269                 .setAckFinalIndicator(ResponseCodes.FINAL_ACK_YES).setResponseCode(ResponseCodes.RESPONSE_FAILED)
270                 .setResponseMessage("PCE calculation failed").build();
271         ResponseParameters reponseParameters = new ResponseParametersBuilder().build();
272         return new PathComputationRequestOutputBuilder().setConfigurationResponseCommon(configurationResponseCommon)
273                 .setResponseParameters(reponseParameters).build();
274     }
275
276     private Boolean validateParams(String serviceName, SdncRequestHeader sdncRequestHeader) {
277         boolean result = true;
278         if (!checkString(serviceName)) {
279             result = false;
280             LOG.error("Service Name (common-id for Temp service) is not set");
281         } else if (sdncRequestHeader == null) {
282             LOG.error("Service sdncRequestHeader 'request-id' is not set");
283             result = false;
284         }
285         return result;
286     }
287
288     private static boolean checkString(String value) {
289         return ((value != null) && (value.compareTo("") != 0));
290     }
291
292     private final class CancelResourceReserveOutputFutureCallback
293             implements FutureCallback<CancelResourceReserveOutput> {
294         private final ServiceNotificationTypes notifType;
295         private final String serviceName;
296         String message = "";
297         ServiceRpcResultSh notification = null;
298
299         private CancelResourceReserveOutputFutureCallback(ServiceNotificationTypes notifType, String serviceName) {
300             this.notifType = notifType;
301             this.serviceName = serviceName;
302         }
303
304         @Override
305         public void onSuccess(CancelResourceReserveOutput response) {
306             if (response != null) {
307                 /**
308                  * If PCE reply is received before timer expiration with a positive result, a
309                  * service is created with admin and operational status 'down'.
310                  */
311                 message = "PCE replied to CRR Request !";
312                 LOG.info("PCE replied to CRR Request : {}", response);
313                 notification =
314                         new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName(serviceName)
315                                 .setStatus(RpcStatusEx.Successful).setStatusMessage(message).build();
316                 try {
317                     notificationPublishService.putNotification(notification);
318                 } catch (InterruptedException e) {
319                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
320                 }
321             } else {
322                 message = "PCE failed ";
323                 notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName("")
324                         .setStatus(RpcStatusEx.Failed).setStatusMessage(message).build();
325                 try {
326                     notificationPublishService.putNotification(notification);
327                 } catch (InterruptedException e) {
328                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
329                 }
330             }
331         }
332
333         @Override
334         public void onFailure(Throwable arg0) {
335             LOG.error("Cancel resource failed !");
336             notification = new ServiceRpcResultShBuilder().setNotificationType(notifType)
337                     .setServiceName(serviceName).setStatus(RpcStatusEx.Failed)
338                     .setStatusMessage("CRR Request failed  : " + arg0.getMessage()).build();
339             try {
340                 notificationPublishService.putNotification(notification);
341             } catch (InterruptedException e) {
342                 LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
343             }
344         }
345     }
346
347     private final class PathComputationRequestOutputCallback implements FutureCallback<PathComputationRequestOutput> {
348         private final ServiceNotificationTypes notifType;
349         private final String serviceName;
350         String message = "";
351         ServiceRpcResultSh notification = null;
352
353         private PathComputationRequestOutputCallback(ServiceNotificationTypes notifType, String serviceName) {
354             this.notifType = notifType;
355             this.serviceName = serviceName;
356         }
357
358         @Override
359         public void onSuccess(PathComputationRequestOutput response) {
360             if (response != null) {
361                 /**
362                  * If PCE reply is received before timer expiration with a positive result, a
363                  * service is created with admin and operational status 'down'.
364                  */
365                 message = "PCE replied to PCR Request !";
366                 LOG.info("PCE replied to PCR Request : {}", response);
367                 notification = new ServiceRpcResultShBuilder().setNotificationType(notifType)
368                         .setServiceName(serviceName)
369                         .setStatus(RpcStatusEx.Successful).setStatusMessage(message).build();
370                 try {
371                     notificationPublishService.putNotification(notification);
372                 } catch (InterruptedException e) {
373                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
374                 }
375             } else {
376                 message = "PCE failed ";
377                 notification = new ServiceRpcResultShBuilder().setNotificationType(notifType).setServiceName("")
378                         .setStatus(RpcStatusEx.Failed).setStatusMessage(message).build();
379                 try {
380                     notificationPublishService.putNotification(notification);
381                 } catch (InterruptedException e) {
382                     LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
383                 }
384             }
385         }
386
387         @Override
388         public void onFailure(Throwable arg0) {
389             LOG.error("Path not calculated..");
390             notification = new ServiceRpcResultShBuilder().setNotificationType(notifType)
391                     .setServiceName(serviceName)
392                     .setStatus(RpcStatusEx.Failed).setStatusMessage("PCR Request failed  : " + arg0.getMessage())
393                     .build();
394             try {
395                 notificationPublishService.putNotification(notification);
396             } catch (InterruptedException e) {
397                 LOG.info(NOTIFICATION_OFFER_REJECTED_MSG, e);
398             }
399         }
400     }
401 }