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