infinite loop when so not responding
[externalapi/nbi.git] / src / main / java / org / onap / nbi / apis / serviceorder / workflow / SOTaskProcessor.java
1 /**
2  * Copyright (c) 2018 Orange
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11  * specific language governing permissions and limitations under the License.
12  */
13 package org.onap.nbi.apis.serviceorder.workflow;
14
15 import org.onap.nbi.apis.serviceorder.SoClient;
16 import org.onap.nbi.apis.serviceorder.model.ServiceCharacteristic;
17 import org.onap.nbi.apis.serviceorder.model.ServiceOrder;
18 import org.onap.nbi.apis.serviceorder.model.ServiceOrderItem;
19 import org.onap.nbi.apis.serviceorder.model.StateType;
20 import org.onap.nbi.apis.serviceorder.model.consumer.*;
21 import org.onap.nbi.apis.serviceorder.model.orchestrator.ExecutionTask;
22 import org.onap.nbi.apis.serviceorder.model.orchestrator.ServiceOrderInfo;
23 import org.onap.nbi.apis.serviceorder.repositories.ExecutionTaskRepository;
24 import org.onap.nbi.apis.serviceorder.repositories.ServiceOrderRepository;
25 import org.onap.nbi.apis.serviceorder.utils.JsonEntityConverter;
26 import org.onap.nbi.exceptions.TechnicalException;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.springframework.beans.factory.annotation.Autowired;
30 import org.springframework.beans.factory.annotation.Value;
31 import org.springframework.http.HttpStatus;
32 import org.springframework.http.ResponseEntity;
33 import org.springframework.stereotype.Service;
34 import org.springframework.util.CollectionUtils;
35
36 import java.io.IOException;
37 import java.util.*;
38
39 @Service
40 public class SOTaskProcessor {
41
42     @Value("${nbi.callForVNF}")
43     private boolean enableCallForVNF;
44
45     @Value("${onap.lcpCloudRegionId}")
46     private String lcpCloudRegionId;
47
48     @Value("${onap.tenantId}")
49     private String tenantId;
50
51     @Autowired
52     private ServiceOrderRepository serviceOrderRepository;
53
54     @Autowired
55     private ExecutionTaskRepository executionTaskRepository;
56
57     @Autowired
58     private SoClient soClient;
59
60
61     private static final Logger LOGGER = LoggerFactory.getLogger(SOTaskProcessor.class);
62
63     /**
64      * Run the ServiceOrchestrator processing for a serviceOrderItem which with any sub relations
65      *
66      * @throws InterruptedException
67      */
68     public void processOrderItem(ExecutionTask executionTask) throws InterruptedException {
69
70         ServiceOrderInfo serviceOrderInfo = getServiceOrderInfo(executionTask);
71
72         ServiceOrder serviceOrder = serviceOrderRepository.findOne(serviceOrderInfo.getServiceOrderId());
73         ServiceOrderItem serviceOrderItem = getServiceOrderItem(executionTask, serviceOrder);
74
75         if (StateType.ACKNOWLEDGED == serviceOrderItem.getState()) {
76
77             ResponseEntity<CreateServiceInstanceResponse> response = postServiceOrderItem(serviceOrderInfo,
78                 serviceOrderItem);
79             updateServiceOrderItem(response, serviceOrderItem,serviceOrder);
80         }
81
82         if (executionTask.getNbRetries() > 0 && StateType.FAILED != serviceOrderItem.getState()
83             ) {
84             // TODO lancer en asynchrone
85             pollSoRequestStatus(serviceOrderItem);
86             if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
87                 updateSuccessTask(executionTask);
88             } else {
89                 int nbRetries = executionTask.getNbRetries();
90                 executionTask.setNbRetries(--nbRetries);
91                 executionTask.setLastAttemptDate(new Date());
92                 executionTaskRepository.save(executionTask);
93             }
94         } else {
95             updateFailedTask(executionTask, serviceOrder);
96         }
97
98         updateServiceOrder(serviceOrder);
99     }
100
101     private ResponseEntity<CreateServiceInstanceResponse> postServiceOrderItem(ServiceOrderInfo serviceOrderInfo,
102         ServiceOrderItem serviceOrderItem) {
103         ResponseEntity<CreateServiceInstanceResponse> response = null;
104         try {
105             response = postSORequest(serviceOrderItem, serviceOrderInfo);
106         } catch (NullPointerException e) {
107             LOGGER.error("Unable to create service instance for serviceOrderItem.id=" + serviceOrderItem.getId(), e);
108             response = null;
109         }
110         return response;
111     }
112
113     private ServiceOrderItem getServiceOrderItem(ExecutionTask executionTask, ServiceOrder serviceOrder) {
114         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
115             if (item.getId().equals(executionTask.getOrderItemId())) {
116                 return item;
117             }
118         }
119         throw new TechnicalException(
120             "Unable to retrieve serviceOrderItem forexecutionTaskId " + executionTask.getInternalId());
121     }
122
123     private ServiceOrderInfo getServiceOrderInfo(ExecutionTask executionTask) {
124         String serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
125         ServiceOrderInfo serviceOrderInfo = null;
126         try {
127             serviceOrderInfo =
128                 JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson);
129         } catch (IOException e) {
130             LOGGER
131                 .error("Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId(), e);
132             throw new TechnicalException(
133                 "Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId());
134         }
135         return serviceOrderInfo;
136     }
137
138     private ResponseEntity<CreateServiceInstanceResponse> postSORequest(ServiceOrderItem serviceOrderItem,
139         ServiceOrderInfo serviceOrderInfo) {
140         RequestDetails requestDetails = buildSoRequest(serviceOrderItem,
141             serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()).getCatalogResponse(),
142             serviceOrderInfo.getSubscriberInfo());
143         MSOPayload msoPayload = new MSOPayload(requestDetails);
144         ResponseEntity<CreateServiceInstanceResponse> response = null;
145
146         switch (serviceOrderItem.getAction()) {
147             case ADD:
148                 response = soClient.callCreateServiceInstance(msoPayload);
149                 break;
150             case DELETE:
151                 response = soClient.callDeleteServiceInstance(msoPayload, serviceOrderItem.getService().getId());
152                 break;
153             default:
154                 break;
155         }
156         return response;
157     }
158
159     private void updateServiceOrder(ServiceOrder serviceOrder) {
160         boolean atLeastOneCompleted = false;
161         boolean atLeastOneNotFinished = false;
162         boolean atLeastOneFailed = false;
163
164         for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
165             switch (serviceOrderItem.getState()) {
166                 case COMPLETED:
167                     atLeastOneCompleted = true;
168                     break;
169                 case INPROGRESS:
170                 case ACKNOWLEDGED:
171                     atLeastOneNotFinished = true;
172                     break;
173                 case FAILED:
174                     atLeastOneFailed = true;
175                     break;
176                 default:
177                     break;
178
179             }
180         }
181
182         if (atLeastOneNotFinished) {
183             serviceOrder.setState(StateType.INPROGRESS);
184         } else {
185             serviceOrder.setCompletionDateTime(new Date());
186             if (atLeastOneFailed) {
187                 if (!atLeastOneCompleted) {
188                     serviceOrder.setState(StateType.FAILED);
189                 } else {
190                     serviceOrder.setState(StateType.PARTIAL);
191                 }
192             } else {
193                 serviceOrder.setState(StateType.COMPLETED);
194             }
195         }
196         serviceOrderRepository.save(serviceOrder);
197     }
198
199
200     /**
201      * * @param orderItem
202      */
203     private void pollSoRequestStatus(ServiceOrderItem orderItem) throws InterruptedException {
204         boolean stopPolling = false;
205         String requestId = orderItem.getRequestId();
206         GetRequestStatusResponse response = null;
207         int nbRetries = 0;
208
209         while (!stopPolling) {
210             response = soClient.callGetRequestStatus(requestId);
211             if (response != null) {
212                 if (response.getRequest().getRequestStatus().getPercentProgress() != 100) {
213                     nbRetries++;
214                     orderItem.setState(StateType.INPROGRESS);
215                     Thread.sleep(1000);
216                 } else if (RequestState.COMPLETE != response.getRequest().getRequestStatus().getRequestState()) {
217                     orderItem.setState(StateType.FAILED);
218                     stopPolling = true;
219                 } else {
220                     orderItem.setState(StateType.COMPLETED);
221                     stopPolling = true;
222                 }
223             } else {
224                 orderItem.setState(StateType.INPROGRESS);
225                 stopPolling = true;
226             }
227             if (nbRetries == 3) {
228                 stopPolling = true;
229             }
230         }
231     }
232
233     /**
234      * Build SO CREATE request from the ServiceOrder and catalog informations from SDC
235      *
236      * @param orderItem
237      * @param sdcInfos
238      * @param subscriberInfo
239      * @return
240      */
241     private RequestDetails buildSoRequest(ServiceOrderItem orderItem, Map<String, Object> sdcInfos,
242         SubscriberInfo subscriberInfo) {
243         RequestDetails requestDetails = new RequestDetails();
244
245         requestDetails.setSubscriberInfo(subscriberInfo);
246
247         ModelInfo modelInfo = new ModelInfo();
248         modelInfo.setModelType("service");
249         modelInfo.setModelInvariantId((String) sdcInfos.get("invariantUUID"));
250         modelInfo.setModelNameVersionId(orderItem.getService().getServiceSpecification().getId());
251         modelInfo.setModelVersionId(orderItem.getService().getServiceSpecification().getId());
252         modelInfo.setModelName((String) sdcInfos.get("name"));
253         modelInfo.setModelVersion((String) sdcInfos.get("version"));
254         requestDetails.setModelInfo(modelInfo);
255
256         RequestInfo requestInfo = new RequestInfo();
257         requestInfo.setInstanceName(orderItem.getService().getName());
258         requestInfo.setSource("VID");
259         requestInfo.setSuppressRollback(false);
260         requestInfo.setRequestorId("NBI");
261         requestDetails.setRequestInfo(requestInfo);
262
263         RequestParameters requestParameters = new RequestParameters();
264         requestParameters.setSubscriptionServiceType((String) sdcInfos.get("name"));
265         requestParameters.setUserParams(
266             retrieveUserParamsFromServiceCharacteristics(orderItem.getService().getServiceCharacteristic()));
267         requestParameters.setaLaCarte(true);
268         requestDetails.setRequestParameters(requestParameters);
269
270         CloudConfiguration cloudConfiguration = new CloudConfiguration(lcpCloudRegionId, tenantId);
271         requestDetails.setCloudConfiguration(cloudConfiguration);
272         return requestDetails;
273     }
274
275     /**
276      * Build a list of UserParams for the SO request by browsing a list of ServiceCharacteristics from SDC
277      */
278     private List<UserParams> retrieveUserParamsFromServiceCharacteristics(List<ServiceCharacteristic> characteristics) {
279         List<UserParams> userParams = new ArrayList<UserParams>();
280
281         if (!CollectionUtils.isEmpty(characteristics)) {
282             for (ServiceCharacteristic characteristic : characteristics) {
283                 UserParams userParam = new UserParams(characteristic.getName(),
284                     characteristic.getValue().getServiceCharacteristicValue());
285                 userParams.add(userParam);
286             }
287         }
288
289         return userParams;
290     }
291
292
293     /**
294      * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
295      *  @param response
296      * @param orderItem
297      * @param serviceOrder
298      */
299     private void updateServiceOrderItem(ResponseEntity<CreateServiceInstanceResponse> response,
300         ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
301
302         if (response == null) {
303             LOGGER.warn("response=null for serviceOrderItem.id=" + orderItem.getId());
304             orderItem.setState(StateType.FAILED);
305         }
306         else {
307             CreateServiceInstanceResponse createServiceInstanceResponse = response.getBody();
308             if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
309                 orderItem.getService().setId(createServiceInstanceResponse.getRequestReferences().getInstanceId());
310                 orderItem.setRequestId(createServiceInstanceResponse.getRequestReferences().getRequestId());
311             }
312
313             if (response.getStatusCode() != HttpStatus.CREATED || response.getBody() == null
314                 || response.getBody().getRequestReferences() == null) {
315                 orderItem.setState(StateType.FAILED);
316             } else {
317                 orderItem.setState(StateType.INPROGRESS);
318             }
319         }
320         serviceOrderRepository.save(serviceOrder);
321     }
322
323     /**
324      * Update an executionTask in database when it's process with a success
325      *
326      * @param executionTask
327      */
328     private void updateSuccessTask(ExecutionTask executionTask) {
329         executionTaskRepository.delete(executionTask.getInternalId());
330         executionTaskRepository.updateReliedTaskAfterDelete(executionTask.getInternalId());
331
332     }
333
334     /**
335      * @param executionTask
336      * @param serviceOrder
337      */
338     private void updateFailedTask(ExecutionTask executionTask, ServiceOrder serviceOrder) {
339         List<ExecutionTask> executionTasksToDelete = findExecutionTasksRecursively(executionTask);
340         for (ExecutionTask taskId : executionTasksToDelete) {
341             executionTaskRepository.delete(taskId);
342         }
343         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
344             for (ExecutionTask taskToDelete : executionTasksToDelete) {
345                 if (taskToDelete.getOrderItemId().equals(item.getId())) {
346                     item.setState(StateType.FAILED);
347                 }
348             }
349         }
350     }
351
352     /**
353      * @param executionTask
354      * @return
355      */
356     private List<ExecutionTask> findExecutionTasksRecursively(ExecutionTask executionTask) {
357
358         List<ExecutionTask> executionTasks = new ArrayList<>();
359
360         List<ExecutionTask> tasksReliedToAnOrderItemId =
361             executionTaskRepository.findTasksReliedToAnOrderItemId(executionTask.getInternalId());
362
363         if (CollectionUtils.isEmpty(tasksReliedToAnOrderItemId)) {
364             return Arrays.asList(executionTask);
365         } else {
366             for (ExecutionTask task : tasksReliedToAnOrderItemId) {
367                 executionTasks.addAll(findExecutionTasksRecursively(task));
368             }
369         }
370         executionTasks.add(executionTask);
371         return executionTasks;
372     }
373
374
375 }