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