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