update pce yang model
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / service / PathComputationServiceImpl.java
1 /*
2  * Copyright © 2017 AT&T, 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.pce.service;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import com.google.common.util.concurrent.ListeningExecutorService;
12 import com.google.common.util.concurrent.MoreExecutors;
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.concurrent.Callable;
17 import java.util.concurrent.Executors;
18 import java.util.stream.Collectors;
19 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
20 import org.opendaylight.transportpce.common.mapping.PortMapping;
21 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
22 import org.opendaylight.transportpce.pce.PceComplianceCheck;
23 import org.opendaylight.transportpce.pce.PceComplianceCheckResult;
24 import org.opendaylight.transportpce.pce.PceSendingPceRPCs;
25 import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
26 import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
27 import org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.Response;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.CancelResourceReserveInput;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.CancelResourceReserveOutput;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.CancelResourceReserveOutputBuilder;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.PathComputationRequestInput;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.PathComputationRequestOutput;
33 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.PathComputationRequestOutputBuilder;
34 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.ServicePathRpcResult;
35 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.ServicePathRpcResultBuilder;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.gnpy.GnpyResponse;
37 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.gnpy.GnpyResponseBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.gnpy.gnpy.response.response.type.NoPathCaseBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.gnpy.gnpy.response.response.type.PathCaseBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.path.performance.PathPropertiesBuilder;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.path.performance.path.properties.PathMetric;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.path.performance.path.properties.PathMetricBuilder;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.service.path.rpc.result.PathDescription;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615.service.path.rpc.result.PathDescriptionBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.configuration.response.common.ConfigurationResponseCommonBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.AToZDirection;
47 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ZToADirection;
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.ServicePathNotificationTypes;
50 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.response.parameters.sp.ResponseParametersBuilder;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 public class PathComputationServiceImpl implements PathComputationService {
55
56     private static final Logger LOG = LoggerFactory.getLogger(PathComputationServiceImpl.class);
57     private final NotificationPublishService notificationPublishService;
58     private NetworkTransactionService networkTransactionService;
59     private final ListeningExecutorService executor;
60     private ServicePathRpcResult notification = null;
61     private final GnpyConsumer gnpyConsumer;
62     private PortMapping portMapping;
63
64     public PathComputationServiceImpl(NetworkTransactionService networkTransactionService,
65                                       NotificationPublishService notificationPublishService,
66                                       GnpyConsumer gnpyConsumer, PortMapping portMapping) {
67         this.notificationPublishService = notificationPublishService;
68         this.networkTransactionService = networkTransactionService;
69         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
70         this.gnpyConsumer = gnpyConsumer;
71         this.portMapping = portMapping;
72     }
73
74     public void init() {
75         LOG.info("init ...");
76     }
77
78     public void close() {
79         LOG.info("close.");
80     }
81
82     @SuppressFBWarnings(
83         value = "UPM_UNCALLED_PRIVATE_METHOD",
84         justification = "false positive, this method is used by public method cancelResourceReserve")
85     private void sendNotifications(
86             ServicePathNotificationTypes servicePathNotificationTypes,
87             String serviceName,
88             RpcStatusEx rpcStatusEx,
89             String message,
90             PathDescription pathDescription) {
91         ServicePathRpcResultBuilder servicePathRpcResultBuilder =
92             new ServicePathRpcResultBuilder()
93                 .setNotificationType(servicePathNotificationTypes)
94                 .setServiceName(serviceName)
95                 .setStatus(rpcStatusEx)
96                 .setStatusMessage(message);
97         if (pathDescription != null) {
98             servicePathRpcResultBuilder.setPathDescription(pathDescription);
99         }
100         this.notification = servicePathRpcResultBuilder.build();
101         try {
102             notificationPublishService.putNotification(this.notification);
103         } catch (InterruptedException e) {
104             LOG.info("notification offer rejected: ", e);
105         }
106     }
107
108     @Override
109     public ListenableFuture<CancelResourceReserveOutput> cancelResourceReserve(CancelResourceReserveInput input) {
110         LOG.info("cancelResourceReserve");
111         return executor.submit(new Callable<CancelResourceReserveOutput>() {
112
113             @Override
114             public CancelResourceReserveOutput call() throws Exception {
115                 sendNotifications(
116                         ServicePathNotificationTypes.CancelResourceReserve,
117                         input.getServiceName(),
118                         RpcStatusEx.Pending,
119                         "Service compliant, submitting cancelResourceReserve Request ...",
120                         null);
121                 PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(gnpyConsumer);
122                 sendingPCE.cancelResourceReserve();
123                 LOG.info("in PathComputationServiceImpl : {}",
124                         Boolean.TRUE.equals(sendingPCE.getSuccess())
125                             ? "ResourceReserve cancelled !"
126                             : "Cancelling ResourceReserve failed !");
127                 sendNotifications(
128                         ServicePathNotificationTypes.CancelResourceReserve,
129                         input.getServiceName(),
130                         RpcStatusEx.Successful,
131                         "cancel Resource Reserve successful!",
132                         null);
133                 return new CancelResourceReserveOutputBuilder()
134                     .setConfigurationResponseCommon(
135                         new ConfigurationResponseCommonBuilder()
136                             .setAckFinalIndicator("Yes")
137                             .setRequestId(input.getServiceHandlerHeader().getRequestId())
138                             .setResponseCode("200")
139                             .setResponseMessage("")
140                             .build())
141                     .build();
142             }
143         });
144     }
145
146     @Override
147     public ListenableFuture<PathComputationRequestOutput> pathComputationRequest(PathComputationRequestInput input) {
148         LOG.info("pathComputationRequest");
149         return executor.submit(new Callable<PathComputationRequestOutput>() {
150
151             @Override
152             public PathComputationRequestOutput call() throws Exception {
153                 PathComputationRequestOutputBuilder output = new PathComputationRequestOutputBuilder();
154                 ConfigurationResponseCommonBuilder configurationResponseCommon =
155                         new ConfigurationResponseCommonBuilder();
156                 PceComplianceCheckResult check = PceComplianceCheck.check(input);
157                 if (!check.hasPassed()) {
158                     LOG.error("Path not calculated, service not compliant : {}", check.getMessage());
159                     sendNotifications(
160                         ServicePathNotificationTypes.PathComputationRequest,
161                         input.getServiceName(),
162                         RpcStatusEx.Failed,
163                         "Path not calculated, service not compliant",
164                         null);
165                     configurationResponseCommon
166                             .setAckFinalIndicator("Yes")
167                             .setRequestId(input.getServiceHandlerHeader().getRequestId())
168                             .setResponseCode("Path not calculated")
169                             .setResponseMessage(check.getMessage());
170                     return output
171                         .setConfigurationResponseCommon(configurationResponseCommon.build())
172                         .setResponseParameters(null)
173                         .build();
174                 }
175                 sendNotifications(
176                     ServicePathNotificationTypes.PathComputationRequest,
177                     input.getServiceName(),
178                     RpcStatusEx.Pending,
179                     "Service compliant, submitting pathComputation Request ...",
180                     null);
181                 PceSendingPceRPCs sendingPCE =
182                     new PceSendingPceRPCs(input, networkTransactionService, gnpyConsumer, portMapping);
183                 sendingPCE.pathComputation();
184                 String message = sendingPCE.getMessage();
185                 String responseCode = sendingPCE.getResponseCode();
186                 LOG.info("PCE response: {} {}", message, responseCode);
187
188                 //add the GNPy result
189                 GnpyResult gnpyAtoZ = sendingPCE.getGnpyAtoZ();
190                 GnpyResult gnpyZtoA = sendingPCE.getGnpyZtoA();
191                 List<GnpyResponse> listResponse = new ArrayList<>();
192                 if (gnpyAtoZ != null) {
193                     GnpyResponse respAtoZ = generateGnpyResponse(gnpyAtoZ.getResponse(),"A-to-Z");
194                     listResponse.add(respAtoZ);
195                 }
196                 if (gnpyZtoA != null) {
197                     GnpyResponse respZtoA = generateGnpyResponse(gnpyZtoA.getResponse(),"Z-to-A");
198                     listResponse.add(respZtoA);
199                 }
200                 output
201                     .setGnpyResponse(
202                         listResponse.stream()
203                             .collect(Collectors.toMap(GnpyResponse::key, gnpyResponse -> gnpyResponse)));
204
205                 PathDescriptionBuilder path = sendingPCE.getPathDescription();
206                 if (Boolean.FALSE.equals(sendingPCE.getSuccess()) || (path == null)) {
207                     sendNotifications(
208                         ServicePathNotificationTypes.PathComputationRequest,
209                         input.getServiceName(),
210                         RpcStatusEx.Failed,
211                         "Path not calculated",
212                         null);
213                     return output
214                         .setConfigurationResponseCommon(
215                             configurationResponseCommon
216                                 .setAckFinalIndicator("Yes")
217                                 .setRequestId(input.getServiceHandlerHeader().getRequestId())
218                                 .setResponseCode(responseCode)
219                                 .setResponseMessage(message)
220                                 .build())
221                         .build();
222                 }
223                 // Path calculator returned Success
224                 PathDescription pathDescription =
225                     new org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev220615
226                             .service.path.rpc.result.PathDescriptionBuilder()
227                         .setAToZDirection(path.getAToZDirection())
228                         .setZToADirection(path.getZToADirection())
229                         .build();
230                 sendNotifications(
231                     ServicePathNotificationTypes.PathComputationRequest,
232                     input.getServiceName(),
233                     RpcStatusEx.Successful,
234                     message,
235                     pathDescription);
236                 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
237                         .response.parameters.sp.response.parameters.PathDescription pathDescription1 =
238                     new org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
239                             .response.parameters.sp.response.parameters.PathDescriptionBuilder()
240                         .setAToZDirection(path.getAToZDirection())
241                         .setZToADirection(path.getZToADirection())
242                         .build();
243                 output
244                     .setConfigurationResponseCommon(
245                         configurationResponseCommon
246                             .setAckFinalIndicator("Yes")
247                             .setRequestId(input.getServiceHandlerHeader().getRequestId())
248                             .setResponseCode(responseCode)
249                             .setResponseMessage(message)
250                             .build())
251                     .setResponseParameters(
252                         new ResponseParametersBuilder().setPathDescription(pathDescription1).build());
253                 //debug prints
254                 AToZDirection atoz = pathDescription.getAToZDirection();
255                 if ((atoz != null) && (atoz.getAToZ() != null)) {
256                     LOG.debug("Impl AtoZ Notification: [{}] elements in description", atoz.getAToZ().size());
257                     for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
258                             .path.description.atoz.direction.AToZKey key : atoz.getAToZ().keySet()) {
259                         LOG.debug("Impl AtoZ Notification: [{}] {}", key, atoz.getAToZ().get(key));
260                     }
261                 }
262                 ZToADirection ztoa = pathDescription.getZToADirection();
263                 if ((ztoa != null) && (ztoa.getZToA() != null)) {
264                     LOG.debug("Impl ZtoA Notification: [{}] elements in description", ztoa.getZToA().size());
265                     for (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705
266                             .path.description.ztoa.direction.ZToAKey key : ztoa.getZToA().keySet()) {
267                         LOG.debug("Impl ZtoA Notification: [{}] {}", key, ztoa.getZToA().get(key));
268                     }
269                 }
270                 return output.build();
271             }
272         });
273     }
274
275     public GnpyResponse generateGnpyResponse(Response responseGnpy, String pathDir) {
276         if (responseGnpy == null) {
277             return new GnpyResponseBuilder()
278                 .setPathDir(pathDir)
279                 .setResponseType(null)
280                 .setFeasibility(true)
281                 .build();
282         }
283         if (responseGnpy.getResponseType()
284                 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase) {
285             LOG.info("GNPy : path is not feasible");
286             org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase
287                     noPathGnpy =
288                 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.NoPathCase)
289                     responseGnpy.getResponseType();
290             return new GnpyResponseBuilder()
291                 .setPathDir(pathDir)
292                 .setResponseType(
293                     new NoPathCaseBuilder()
294                         .setNoPath(noPathGnpy.getNoPath())
295                         .build())
296                 .setFeasibility(false)
297                 .build();
298         }
299         if (responseGnpy.getResponseType()
300                 instanceof org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase) {
301             LOG.info("GNPy : path is feasible");
302             org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase
303                     pathCase =
304                 (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.result.response.response.type.PathCase)
305                     responseGnpy.getResponseType();
306             List<org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric>
307                     pathMetricList =
308                 new ArrayList<>(pathCase.getPathProperties().getPathMetric().values());
309             List<PathMetric> gnpyPathMetricList = new ArrayList<>();
310             for (org.opendaylight.yang.gen.v1.gnpy.path.rev220615.generic.path.properties.path.properties.PathMetric
311                     pathMetricGnpy : pathMetricList) {
312                 gnpyPathMetricList.add(
313                     new PathMetricBuilder()
314                         .setMetricType(pathMetricGnpy.getMetricType())
315                         .setAccumulativeValue(pathMetricGnpy.getAccumulativeValue())
316                         .build());
317             }
318             return new GnpyResponseBuilder()
319                 .setPathDir(pathDir)
320                 .setResponseType(
321                     new PathCaseBuilder()
322                         .setPathProperties(
323                             new PathPropertiesBuilder()
324                                 .setPathMetric(gnpyPathMetricList.stream()
325                                     .collect(Collectors.toMap(PathMetric::key, pathMetric -> pathMetric)))
326                                 .build())
327                         .build())
328                 .setFeasibility(true)
329                 .build();
330         }
331         return new GnpyResponseBuilder()
332             .setPathDir(pathDir)
333             .setResponseType(null)
334             .setFeasibility(true)
335             .build();
336     }
337
338 }