2 * Copyright (c) 2018 Orange
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
13 package org.onap.nbi.apis.serviceorder.workflow;
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.service.ServiceOrderService;
25 import org.onap.nbi.apis.serviceorder.utils.E2EServiceUtils;
26 import org.onap.nbi.apis.serviceorder.utils.JsonEntityConverter;
27 import org.onap.nbi.exceptions.TechnicalException;
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;
37 import java.io.IOException;
41 public class SOTaskProcessor {
43 @Value("${nbi.callForVNF}")
44 private boolean enableCallForVNF;
46 @Value("${onap.lcpCloudRegionId}")
47 private String lcpCloudRegionId;
49 @Value("${onap.tenantId}")
50 private String tenantId;
52 @Value("${so.owning.entity.id}")
53 private String soOwningEntityId;
55 @Value("${so.owning.entity.name}")
56 private String soOwningEntityName;
58 @Value("${so.project.name}")
59 private String soProjectName;
63 private ServiceOrderService serviceOrderService;
66 private ExecutionTaskRepository executionTaskRepository;
69 private SoClient soClient;
72 private static final Logger LOGGER = LoggerFactory.getLogger(SOTaskProcessor.class);
75 * Run the ServiceOrchestrator processing for a serviceOrderItem which with any sub relations
77 * @throws InterruptedException
79 public void processOrderItem(ExecutionTask executionTask) throws InterruptedException {
81 ServiceOrderInfo serviceOrderInfo = getServiceOrderInfo(executionTask);
83 ServiceOrder serviceOrder = serviceOrderService.findServiceOrderById(serviceOrderInfo.getServiceOrderId());
84 ServiceOrderItem serviceOrderItem = getServiceOrderItem(executionTask, serviceOrder);
85 boolean e2eService = E2EServiceUtils.isE2EService(serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()));
87 if (StateType.ACKNOWLEDGED == serviceOrderItem.getState()) {
89 ResponseEntity<CreateE2EServiceInstanceResponse> response = postE2EServiceOrderItem(serviceOrderInfo,
90 serviceOrderItem, serviceOrder);
91 updateE2EServiceOrderItem(response, serviceOrderItem, serviceOrder);
94 ResponseEntity<CreateServiceInstanceResponse> response = postServiceOrderItem(serviceOrderInfo,serviceOrder,
96 updateServiceOrderItem(response, serviceOrderItem,serviceOrder);
100 if (executionTask.getNbRetries() > 0 && StateType.FAILED != serviceOrderItem.getState()
102 // TODO lancer en asynchrone
104 pollE2ESoRequestStatus(serviceOrder, serviceOrderItem);
106 pollSoRequestStatus(serviceOrder, serviceOrderItem);
108 if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
109 updateSuccessTask(executionTask);
111 int nbRetries = executionTask.getNbRetries();
112 executionTask.setNbRetries(--nbRetries);
113 executionTask.setLastAttemptDate(new Date());
114 executionTaskRepository.save(executionTask);
117 updateFailedTask(executionTask, serviceOrder);
120 updateServiceOrder(serviceOrder);
123 private ResponseEntity<CreateServiceInstanceResponse> postServiceOrderItem(ServiceOrderInfo serviceOrderInfo,
124 ServiceOrder serviceOrder, ServiceOrderItem serviceOrderItem) {
125 ResponseEntity<CreateServiceInstanceResponse> response = null;
127 response = postSORequest(serviceOrderItem,serviceOrder, serviceOrderInfo);
128 } catch (NullPointerException e) {
129 LOGGER.error("Unable to create service instance for serviceOrderItem.id=" + serviceOrderItem.getId(), e);
135 private ResponseEntity<CreateE2EServiceInstanceResponse> postE2EServiceOrderItem(ServiceOrderInfo serviceOrderInfo,
136 ServiceOrderItem serviceOrderItem, ServiceOrder serviceOrder) {
137 ResponseEntity<CreateE2EServiceInstanceResponse> response;
139 response = postE2ESORequest(serviceOrderItem, serviceOrderInfo, serviceOrder);
140 } catch (NullPointerException e) {
141 LOGGER.error("Unable to create service instance for serviceOrderItem.id=" + serviceOrderItem.getId(), e);
147 private ServiceOrderItem getServiceOrderItem(ExecutionTask executionTask, ServiceOrder serviceOrder) {
148 for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
149 if (item.getId().equals(executionTask.getOrderItemId())) {
153 throw new TechnicalException(
154 "Unable to retrieve serviceOrderItem forexecutionTaskId " + executionTask.getInternalId());
157 private ServiceOrderInfo getServiceOrderInfo(ExecutionTask executionTask) {
158 String serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
159 ServiceOrderInfo serviceOrderInfo = null;
162 JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson);
163 } catch (IOException e) {
165 .error("Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId(), e);
166 throw new TechnicalException(
167 "Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId());
169 return serviceOrderInfo;
172 private ResponseEntity<CreateServiceInstanceResponse> postSORequest(ServiceOrderItem serviceOrderItem,
173 ServiceOrder serviceOrder, ServiceOrderInfo serviceOrderInfo) {
174 RequestDetails requestDetails = buildSoRequest(serviceOrderItem,
175 serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()).getCatalogResponse(),
176 serviceOrderInfo.getSubscriberInfo());
177 MSOPayload msoPayload = new MSOPayload(requestDetails);
178 ResponseEntity<CreateServiceInstanceResponse> response = null;
180 switch (serviceOrderItem.getAction()) {
182 response = soClient.callCreateServiceInstance(msoPayload);
185 response = soClient.callDeleteServiceInstance(msoPayload,serviceOrderItem.getService().getId());
190 buildOrderMessageIfNeeded(serviceOrderItem, serviceOrder, response);
194 private void buildOrderMessageIfNeeded(ServiceOrderItem serviceOrderItem, ServiceOrder serviceOrder,
195 ResponseEntity<?> response) {
198 if(response.getStatusCode()== HttpStatus.INTERNAL_SERVER_ERROR) {
199 serviceOrderService.addOrderMessage(serviceOrder, "502");
201 if(response.getStatusCode()== HttpStatus.BAD_REQUEST) {
202 ResponseEntity<?> messageError=response;
203 if(messageError.getBody().toString().toLowerCase().contains("serviceinstance already exists")){
204 serviceOrderService.addOrderItemMessage(serviceOrder, serviceOrderItem, "105");
210 private ResponseEntity<CreateE2EServiceInstanceResponse> postE2ESORequest(ServiceOrderItem serviceOrderItem,
211 ServiceOrderInfo serviceOrderInfo, ServiceOrder serviceOrder) {
212 ServiceModel service = buildE2ESoRequest(serviceOrderItem, serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()).getCatalogResponse(), serviceOrderInfo.getSubscriberInfo(), serviceOrder);
213 MSOE2EPayload msoE2EPayload = new MSOE2EPayload(service);
214 ResponseEntity<CreateE2EServiceInstanceResponse> response = null;
215 switch (serviceOrderItem.getAction()) {
217 response = soClient.callE2ECreateServiceInstance(msoE2EPayload);
220 response = soClient.callE2EDeleteServiceInstance(service.getGlobalSubscriberId(), service.getServiceType(),serviceOrderItem.getService().getId());
225 buildOrderMessageIfNeeded(serviceOrderItem, serviceOrder, response);
229 private void updateServiceOrder(ServiceOrder serviceOrder) {
230 boolean atLeastOneCompleted = false;
231 boolean atLeastOneNotFinished = false;
232 boolean atLeastOneFailed = false;
234 for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
235 switch (serviceOrderItem.getState()) {
237 atLeastOneCompleted = true;
241 atLeastOneNotFinished = true;
244 atLeastOneFailed = true;
252 if (atLeastOneNotFinished) {
253 serviceOrderService.updateOrderState(serviceOrder,StateType.INPROGRESS);
255 StateType finalState;
256 if (atLeastOneFailed) {
257 if (!atLeastOneCompleted) {
258 finalState=StateType.FAILED;
260 finalState=StateType.PARTIAL;
263 finalState=StateType.COMPLETED;
265 serviceOrderService.updateOrderState(serviceOrder,finalState);
273 private void pollSoRequestStatus(ServiceOrder serviceOrder,
274 ServiceOrderItem orderItem) throws InterruptedException {
275 boolean stopPolling = false;
276 String requestId = orderItem.getRequestId();
277 GetRequestStatusResponse response = null;
280 while (!stopPolling) {
281 response = soClient.callGetRequestStatus(requestId);
282 if (response != null) {
283 if (response.getRequest().getRequestStatus().getPercentProgress() != 100) {
285 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.INPROGRESS);
287 LOGGER.debug("orderitem id {} still in progress from so",orderItem.getId());
288 } else if (RequestState.COMPLETE != response.getRequest().getRequestStatus().getRequestState()) {
289 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.FAILED);
291 LOGGER.debug("orderitem id {} failed, response from request status {}",orderItem.getId(),response.getRequest().getRequestStatus().getRequestState());
293 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.COMPLETED);
295 LOGGER.debug("orderitem id {} completed");
298 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.INPROGRESS);
300 LOGGER.debug("orderitem id {} still in progress from so",orderItem.getId());
302 if (nbRetries == 3) {
304 LOGGER.debug("orderitem id {} stop polling from getrequeststatus, 3 retries done",orderItem.getId());
310 private void pollE2ESoRequestStatus(ServiceOrder serviceOrder, ServiceOrderItem orderItem) throws InterruptedException {
311 boolean stopPolling = false;
312 String operationId = orderItem.getRequestId();
313 String serviceId = orderItem.getService().getId();
315 GetE2ERequestStatusResponse response = null;
316 final String ERROR = "error";
317 final String FINISHED = "finished";
318 final String PROCESSING = "processing";
319 String result = null;
320 while (!stopPolling) {
321 response = soClient.callE2EGetRequestStatus(operationId, serviceId);
322 if (response != null) {
323 result = response.getOperation().getResult();
324 if (PROCESSING.equals(result)) {
326 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.INPROGRESS);
328 LOGGER.debug("orderitem id {} still in progress from so",orderItem.getId());
329 } else if (ERROR.equals(result)) {
330 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.FAILED);
332 LOGGER.debug("orderitem id {} failed, response from request status {}",orderItem.getId(),response.getOperation().getResult());
333 } else if (FINISHED.equals(result)) {
334 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.COMPLETED);
336 LOGGER.debug("orderitem id {} completed");
339 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.INPROGRESS);
341 LOGGER.debug("orderitem id {} still in progress from so",orderItem.getId());
343 if (nbRetries == 3) {
345 LOGGER.debug("orderitem id {} stop polling from getrequeststatus, 3 retries done",orderItem.getId());
352 * Build SO CREATE request from the ServiceOrder and catalog informations from SDC
356 * @param subscriberInfo
359 private RequestDetails buildSoRequest(ServiceOrderItem orderItem, Map<String, Object> sdcInfos,
360 SubscriberInfo subscriberInfo) {
361 RequestDetails requestDetails = new RequestDetails();
363 requestDetails.setSubscriberInfo(subscriberInfo);
365 ModelInfo modelInfo = new ModelInfo();
366 modelInfo.setModelType("service");
367 modelInfo.setModelInvariantId((String) sdcInfos.get("invariantUUID"));
368 modelInfo.setModelNameVersionId(orderItem.getService().getServiceSpecification().getId());
369 modelInfo.setModelVersionId(orderItem.getService().getServiceSpecification().getId());
370 modelInfo.setModelName((String) sdcInfos.get("name"));
371 modelInfo.setModelVersion((String) sdcInfos.get("version"));
372 requestDetails.setModelInfo(modelInfo);
374 RequestInfo requestInfo = new RequestInfo();
375 requestInfo.setInstanceName(orderItem.getService().getName());
376 requestInfo.setSource("VID");
377 requestInfo.setSuppressRollback(false);
378 requestInfo.setRequestorId("NBI");
379 requestDetails.setRequestInfo(requestInfo);
381 RequestParameters requestParameters = new RequestParameters();
382 requestParameters.setSubscriptionServiceType((String) sdcInfos.get("name"));
383 requestParameters.setUserParams(
384 retrieveUserParamsFromServiceCharacteristics(orderItem.getService().getServiceCharacteristic()));
385 requestParameters.setaLaCarte(true);
386 requestDetails.setRequestParameters(requestParameters);
388 CloudConfiguration cloudConfiguration = new CloudConfiguration(lcpCloudRegionId, tenantId);
389 requestDetails.setCloudConfiguration(cloudConfiguration);
391 OwningEntity owningEntity = new OwningEntity();
392 owningEntity.setOwningEntityId(soOwningEntityId);
393 owningEntity.setOwningEntityName(soOwningEntityName);
394 requestDetails.setOwningEntity(owningEntity);
396 Project project = new Project();
397 project.setProjectName(soProjectName);
399 requestDetails.setProject(project);
401 return requestDetails;
405 * Build E2E SO CREATE request from the ServiceOrder and catalog informations from SDC
407 * @param serviceOrderItem
408 * @param serviceOrder
412 //ServiceOrderItem serviceOrderItem --> orderItem?
413 private ServiceModel buildE2ESoRequest(ServiceOrderItem serviceOrderItem, Map<String, Object> sdcInfos,
414 SubscriberInfo subscriberInfo, ServiceOrder serviceOrder) {
416 subscriberInfo.getGlobalSubscriberId();
417 ServiceModel service = new ServiceModel();
418 service.setName(serviceOrderItem.getService().getName());
419 service.setDescription(serviceOrder.getDescription());
420 service.setServiceUuid(serviceOrderItem.getService().getServiceSpecification().getId());
421 service.setServiceInvariantUuid((String) sdcInfos.get("invariantUUID"));
422 service.setGlobalSubscriberId(subscriberInfo.getGlobalSubscriberId());
423 service.setServiceType((String) sdcInfos.get("name"));
425 ParametersModel parameters = new ParametersModel();
426 ArrayList<ResourceModel> resources = new ArrayList();
428 ArrayList<Object> resourceObjects = (ArrayList<Object>)sdcInfos.get("resourceSpecification");
430 for(int i = 0; i < resourceObjects.size(); i++) {
432 ResourceModel resourceModel = new ResourceModel((Map<String, Object>)resourceObjects.get(i));
433 ParametersModel resourceParameters = new ParametersModel();
434 resourceModel.setParameters(resourceParameters);
435 resources.add(resourceModel);
438 parameters.setResources(resources);
439 List<UserParams> userParams = retrieveUserParamsFromServiceCharacteristics(serviceOrderItem.getService().getServiceCharacteristic());
441 // If there are ServiceCharacteristics add them to requestInputs
442 if (!userParams.isEmpty()){
443 Map<String, String> requestInputs = new HashMap<String, String>();
444 for (int i = 0; i < userParams.size(); i++) {
445 requestInputs.put(userParams.get(i).getName(), userParams.get(i).getValue());
448 parameters.setRequestInputs(requestInputs);
450 service.setParameters(parameters);
456 * Build a list of UserParams for the SO request by browsing a list of ServiceCharacteristics from SDC
458 private List<UserParams> retrieveUserParamsFromServiceCharacteristics(List<ServiceCharacteristic> characteristics) {
459 List<UserParams> userParams = new ArrayList<>();
461 if (!CollectionUtils.isEmpty(characteristics)) {
462 for (ServiceCharacteristic characteristic : characteristics) {
463 UserParams userParam = new UserParams(characteristic.getName(),
464 characteristic.getValue().getServiceCharacteristicValue());
465 userParams.add(userParam);
474 * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
477 * @param serviceOrder
479 private void updateServiceOrderItem(ResponseEntity<CreateServiceInstanceResponse> response,
480 ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
482 if (response==null || !response.getStatusCode().is2xxSuccessful()) {
483 LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
484 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.FAILED);
487 CreateServiceInstanceResponse createServiceInstanceResponse = response.getBody();
488 if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
489 orderItem.getService().setId(createServiceInstanceResponse.getRequestReferences().getInstanceId());
490 orderItem.setRequestId(createServiceInstanceResponse.getRequestReferences().getRequestId());
493 if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
494 || response.getBody().getRequestReferences() == null) {
495 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.FAILED);
496 LOGGER.warn("order item {} failed , status {} , response {}",orderItem.getId(),response.getStatusCode(),response.getBody());
498 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.INPROGRESS);
504 * Update E2EServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
507 * @param serviceOrder
509 private void updateE2EServiceOrderItem(ResponseEntity<CreateE2EServiceInstanceResponse> response,
510 ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
512 if (response==null || !response.getStatusCode().is2xxSuccessful()) {
513 LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
514 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.FAILED);
517 CreateE2EServiceInstanceResponse createE2EServiceInstanceResponse = response.getBody();
518 if (createE2EServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
519 orderItem.getService().setId(createE2EServiceInstanceResponse.getService().getServiceId());
520 orderItem.setRequestId(createE2EServiceInstanceResponse.getService().getOperationId());
523 if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
524 || response.getBody().getService().getOperationId() == null || response.getBody().getService().getServiceId() == null) {
525 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.FAILED);
526 LOGGER.warn("order item {} failed , status {} , response {}",orderItem.getId(),response.getStatusCode(),response.getBody());
528 serviceOrderService.updateOrderItemState(serviceOrder,orderItem,StateType.INPROGRESS);
534 * Update an executionTask in database when it's process with a success
536 * @param executionTask
538 private void updateSuccessTask(ExecutionTask executionTask) {
539 executionTaskRepository.delete(executionTask.getInternalId());
540 executionTaskRepository.updateReliedTaskAfterDelete(executionTask.getInternalId());
545 * @param executionTask
546 * @param serviceOrder
548 private void updateFailedTask(ExecutionTask executionTask, ServiceOrder serviceOrder) {
549 List<ExecutionTask> executionTasksToDelete = findExecutionTasksRecursively(executionTask);
550 for (ExecutionTask taskId : executionTasksToDelete) {
551 executionTaskRepository.delete(taskId);
552 LOGGER.warn("task {} with orderitem id {} deleted cause orderitem id {} failed ",taskId.getInternalId(),taskId.getOrderItemId(),executionTask.getOrderItemId());
554 for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
555 for (ExecutionTask taskToDelete : executionTasksToDelete) {
556 if (taskToDelete.getOrderItemId().equals(item.getId())) {
557 serviceOrderService.updateOrderItemState(serviceOrder,item,StateType.FAILED);
558 LOGGER.warn("task {} with orderitem id {} to failed cause orderitem id {} failed ",taskToDelete.getInternalId(),taskToDelete.getOrderItemId(),executionTask.getOrderItemId());
566 * @param executionTask
569 private List<ExecutionTask> findExecutionTasksRecursively(ExecutionTask executionTask) {
571 List<ExecutionTask> executionTasks = new ArrayList<>();
573 List<ExecutionTask> tasksReliedToAnOrderItemId =
574 executionTaskRepository.findTasksReliedToAnOrderItemId(executionTask.getInternalId());
576 if (CollectionUtils.isEmpty(tasksReliedToAnOrderItemId)) {
577 return Arrays.asList(executionTask);
579 for (ExecutionTask task : tasksReliedToAnOrderItemId) {
580 executionTasks.addAll(findExecutionTasksRecursively(task));
583 executionTasks.add(executionTask);
584 return executionTasks;