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