d63de11ecd503592df90c4be5cd73a2c6a4f9507
[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
80             if (response == null) {
81                 LOGGER.warn("response=null for serviceOrderItem.id=" + serviceOrderItem.getId());
82                 serviceOrderItem.setState(StateType.FAILED);
83             } else {
84                 updateServiceOrderItem(response, serviceOrderItem);
85             }
86         }
87
88         if (executionTask.getNbRetries() > 0 && StateType.FAILED != serviceOrderItem.getState()
89             ) {
90             // TODO lancer en asynchrone
91             pollSoRequestStatus(serviceOrderItem);
92             if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
93                 updateSuccessTask(executionTask);
94             } else {
95                 int nbRetries = executionTask.getNbRetries();
96                 executionTask.setNbRetries(--nbRetries);
97                 executionTask.setLastAttemptDate(new Date());
98                 executionTaskRepository.save(executionTask);
99             }
100         } else {
101             updateFailedTask(executionTask, serviceOrder);
102         }
103
104         updateServiceOrder(serviceOrder);
105     }
106
107     private ResponseEntity<CreateServiceInstanceResponse> postServiceOrderItem(ServiceOrderInfo serviceOrderInfo,
108         ServiceOrderItem serviceOrderItem) {
109         ResponseEntity<CreateServiceInstanceResponse> response = null;
110         try {
111             response = postSORequest(serviceOrderItem, serviceOrderInfo);
112         } catch (NullPointerException e) {
113             LOGGER.error("Unable to create service instance for serviceOrderItem.id=" + serviceOrderItem.getId(), e);
114             response = null;
115         }
116         return response;
117     }
118
119     private ServiceOrderItem getServiceOrderItem(ExecutionTask executionTask, ServiceOrder serviceOrder) {
120         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
121             if (item.getId().equals(executionTask.getOrderItemId())) {
122                 return item;
123             }
124         }
125         throw new TechnicalException(
126             "Unable to retrieve serviceOrderItem forexecutionTaskId " + executionTask.getInternalId());
127     }
128
129     private ServiceOrderInfo getServiceOrderInfo(ExecutionTask executionTask) {
130         String serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
131         ServiceOrderInfo serviceOrderInfo = null;
132         try {
133             serviceOrderInfo =
134                 JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson);
135         } catch (IOException e) {
136             LOGGER
137                 .error("Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId(), e);
138             throw new TechnicalException(
139                 "Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId());
140         }
141         return serviceOrderInfo;
142     }
143
144     private ResponseEntity<CreateServiceInstanceResponse> postSORequest(ServiceOrderItem serviceOrderItem,
145         ServiceOrderInfo serviceOrderInfo) {
146         RequestDetails requestDetails = buildSoRequest(serviceOrderItem,
147             serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()).getCatalogResponse(),
148             serviceOrderInfo.getSubscriberInfo());
149         MSOPayload msoPayload = new MSOPayload(requestDetails);
150         ResponseEntity<CreateServiceInstanceResponse> response = null;
151
152         switch (serviceOrderItem.getAction()) {
153             case ADD:
154                 response = soClient.callCreateServiceInstance(msoPayload);
155                 break;
156             case DELETE:
157                 response = soClient.callDeleteServiceInstance(msoPayload, serviceOrderItem.getService().getId());
158                 break;
159             default:
160                 break;
161         }
162         return response;
163     }
164
165     private void updateServiceOrder(ServiceOrder serviceOrder) {
166         boolean atLeastOneCompleted = false;
167         boolean atLeastOneNotFinished = false;
168         boolean atLeastOneFailed = false;
169
170         for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
171             switch (serviceOrderItem.getState()) {
172                 case COMPLETED:
173                     atLeastOneCompleted = true;
174                     break;
175                 case INPROGRESS:
176                 case ACKNOWLEDGED:
177                     atLeastOneNotFinished = true;
178                     break;
179                 case FAILED:
180                     atLeastOneFailed = true;
181                     break;
182                 default:
183                     break;
184
185             }
186         }
187
188         if (atLeastOneNotFinished) {
189             serviceOrder.setState(StateType.INPROGRESS);
190         } else {
191             serviceOrder.setCompletionDateTime(new Date());
192             if (atLeastOneFailed) {
193                 if (!atLeastOneCompleted) {
194                     serviceOrder.setState(StateType.FAILED);
195                 } else {
196                     serviceOrder.setState(StateType.PARTIAL);
197                 }
198             } else {
199                 serviceOrder.setState(StateType.COMPLETED);
200             }
201         }
202         serviceOrderRepository.save(serviceOrder);
203     }
204
205
206     /**
207      * * @param orderItem
208      */
209     private void pollSoRequestStatus(ServiceOrderItem orderItem) throws InterruptedException {
210         boolean stopPolling = false;
211         String requestId = orderItem.getRequestId();
212         GetRequestStatusResponse response = null;
213         int nbRetries = 0;
214
215         while (!stopPolling) {
216             response = soClient.callGetRequestStatus(requestId);
217             if (response != null) {
218                 if (response.getRequest().getRequestStatus().getPercentProgress() != 100) {
219                     nbRetries++;
220                     orderItem.setState(StateType.INPROGRESS);
221                     Thread.sleep(1000);
222                 } else if (RequestState.COMPLETE != response.getRequest().getRequestStatus().getRequestState()) {
223                     orderItem.setState(StateType.FAILED);
224                     stopPolling = true;
225                 } else {
226                     orderItem.setState(StateType.COMPLETED);
227                     stopPolling = true;
228                 }
229             } else {
230                 orderItem.setState(StateType.INPROGRESS);
231                 stopPolling = true;
232             }
233             if (nbRetries == 3) {
234                 stopPolling = true;
235             }
236         }
237     }
238
239     /**
240      * Build SO CREATE request from the ServiceOrder and catalog informations from SDC
241      *
242      * @param orderItem
243      * @param sdcInfos
244      * @param subscriberInfo
245      * @return
246      */
247     private RequestDetails buildSoRequest(ServiceOrderItem orderItem, Map<String, Object> sdcInfos,
248         SubscriberInfo subscriberInfo) {
249         RequestDetails requestDetails = new RequestDetails();
250
251         requestDetails.setSubscriberInfo(subscriberInfo);
252
253         ModelInfo modelInfo = new ModelInfo();
254         modelInfo.setModelType("service");
255         modelInfo.setModelInvariantId((String) sdcInfos.get("invariantUUID"));
256         modelInfo.setModelNameVersionId(orderItem.getService().getServiceSpecification().getId());
257         modelInfo.setModelVersionId(orderItem.getService().getServiceSpecification().getId());
258         modelInfo.setModelName((String) sdcInfos.get("name"));
259         modelInfo.setModelVersion((String) sdcInfos.get("version"));
260         requestDetails.setModelInfo(modelInfo);
261
262         RequestInfo requestInfo = new RequestInfo();
263         requestInfo.setInstanceName(orderItem.getService().getName());
264         requestInfo.setSource("VID");
265         requestInfo.setSuppressRollback(false);
266         requestInfo.setRequestorId("NBI");
267         requestDetails.setRequestInfo(requestInfo);
268
269         RequestParameters requestParameters = new RequestParameters();
270         requestParameters.setSubscriptionServiceType((String) sdcInfos.get("name"));
271         requestParameters.setUserParams(
272             retrieveUserParamsFromServiceCharacteristics(orderItem.getService().getServiceCharacteristic()));
273         requestParameters.setaLaCarte(true);
274         requestDetails.setRequestParameters(requestParameters);
275
276         CloudConfiguration cloudConfiguration = new CloudConfiguration(lcpCloudRegionId, tenantId);
277         requestDetails.setCloudConfiguration(cloudConfiguration);
278         return requestDetails;
279     }
280
281     /**
282      * Build a list of UserParams for the SO request by browsing a list of ServiceCharacteristics from SDC
283      */
284     private List<UserParams> retrieveUserParamsFromServiceCharacteristics(List<ServiceCharacteristic> characteristics) {
285         List<UserParams> userParams = new ArrayList<UserParams>();
286
287         if (!CollectionUtils.isEmpty(characteristics)) {
288             for (ServiceCharacteristic characteristic : characteristics) {
289                 UserParams userParam = new UserParams(characteristic.getName(),
290                     characteristic.getValue().getServiceCharacteristicValue());
291                 userParams.add(userParam);
292             }
293         }
294
295         return userParams;
296     }
297
298
299     /**
300      * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
301      *
302      * @param response
303      * @param orderItem
304      */
305     private void updateServiceOrderItem(ResponseEntity<CreateServiceInstanceResponse> response,
306         ServiceOrderItem orderItem) {
307
308         CreateServiceInstanceResponse createServiceInstanceResponse = response.getBody();
309         if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
310             orderItem.getService().setId(createServiceInstanceResponse.getRequestReferences().getInstanceId());
311             orderItem.setRequestId(createServiceInstanceResponse.getRequestReferences().getRequestId());
312         }
313
314         if (response.getStatusCode() != HttpStatus.CREATED || response.getBody() == null
315             || response.getBody().getRequestReferences() == null) {
316             orderItem.setState(StateType.FAILED);
317         } else {
318             orderItem.setState(StateType.INPROGRESS);
319         }
320     }
321
322     /**
323      * Update an executionTask in database when it's process with a success
324      *
325      * @param executionTask
326      */
327     private void updateSuccessTask(ExecutionTask executionTask) {
328         executionTaskRepository.delete(executionTask.getInternalId());
329         executionTaskRepository.updateReliedTaskAfterDelete(executionTask.getInternalId());
330
331     }
332
333     /**
334      * @param executionTask
335      * @param serviceOrder
336      */
337     private void updateFailedTask(ExecutionTask executionTask, ServiceOrder serviceOrder) {
338         List<ExecutionTask> executionTasksToDelete = findExecutionTasksRecursively(executionTask);
339         for (ExecutionTask taskId : executionTasksToDelete) {
340             executionTaskRepository.delete(taskId);
341         }
342         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
343             for (ExecutionTask taskToDelete : executionTasksToDelete) {
344                 if (taskToDelete.getOrderItemId().equals(item.getId())) {
345                     item.setState(StateType.FAILED);
346                 }
347             }
348         }
349     }
350
351     /**
352      * @param executionTask
353      * @return
354      */
355     private List<ExecutionTask> findExecutionTasksRecursively(ExecutionTask executionTask) {
356
357         List<ExecutionTask> executionTasks = new ArrayList<>();
358
359         List<ExecutionTask> tasksReliedToAnOrderItemId =
360             executionTaskRepository.findTasksReliedToAnOrderItemId(executionTask.getInternalId());
361
362         if (CollectionUtils.isEmpty(tasksReliedToAnOrderItemId)) {
363             return Arrays.asList(executionTask);
364         } else {
365             for (ExecutionTask task : tasksReliedToAnOrderItemId) {
366                 executionTasks.addAll(findExecutionTasksRecursively(task));
367             }
368         }
369         executionTasks.add(executionTask);
370         return executionTasks;
371     }
372
373
374 }