14df4e6941fcc8dd8980ac027d1df098d61d045b
[so.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright (c) 2019 Samsung
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.so.adapters.tasks.orchestration;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.StringReader;
27 import java.util.HashMap;
28 import java.util.Map;
29 import java.util.Optional;
30 import javax.xml.bind.JAXB;
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import org.apache.commons.lang3.mutable.MutableBoolean;
34 import org.camunda.bpm.client.task.ExternalTask;
35 import org.camunda.bpm.client.task.ExternalTaskService;
36 import org.onap.so.adapters.network.MsoNetworkAdapterImpl;
37 import org.onap.so.adapters.nwrest.CreateNetworkRequest;
38 import org.onap.so.adapters.nwrest.CreateNetworkResponse;
39 import org.onap.so.adapters.nwrest.DeleteNetworkRequest;
40 import org.onap.so.adapters.nwrest.DeleteNetworkResponse;
41 import org.onap.so.adapters.nwrest.UpdateNetworkRequest;
42 import org.onap.so.adapters.nwrest.UpdateNetworkResponse;
43 import org.onap.so.adapters.vnf.MsoVnfAdapterImpl;
44 import org.onap.so.adapters.vnf.VnfAdapterUtils;
45 import org.onap.so.adapters.vnfrest.CreateVfModuleRequest;
46 import org.onap.so.adapters.vnfrest.CreateVfModuleResponse;
47 import org.onap.so.adapters.vnfrest.CreateVolumeGroupRequest;
48 import org.onap.so.adapters.vnfrest.CreateVolumeGroupResponse;
49 import org.onap.so.adapters.vnfrest.DeleteVfModuleRequest;
50 import org.onap.so.adapters.vnfrest.DeleteVfModuleResponse;
51 import org.onap.so.adapters.vnfrest.DeleteVolumeGroupRequest;
52 import org.onap.so.adapters.vnfrest.DeleteVolumeGroupResponse;
53 import org.onap.so.adapters.vnfrest.VfModuleRollback;
54 import org.onap.so.adapters.vnfrest.VolumeGroupRollback;
55 import org.onap.so.logging.tasks.AuditMDCSetup;
56 import org.onap.so.openstack.beans.NetworkRollback;
57 import org.onap.so.openstack.beans.StackInfo;
58 import org.onap.so.openstack.beans.VnfRollback;
59 import org.onap.so.openstack.exceptions.MsoException;
60 import org.onap.so.openstack.mappers.StackInfoMapper;
61 import org.onap.so.openstack.utils.MsoHeatUtils;
62 import org.onap.so.utils.ExternalTaskUtils;
63 import org.onap.so.utils.RetrySequenceLevel;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66 import org.springframework.beans.factory.annotation.Autowired;
67 import org.springframework.stereotype.Component;
68 import com.woorea.openstack.heat.model.Stack;
69
70 @Component
71 public class PollService extends ExternalTaskUtils {
72
73     private static final Logger logger = LoggerFactory.getLogger(PollService.class);
74
75     @Autowired
76     private MsoVnfAdapterImpl vnfAdapterImpl;
77
78     @Autowired
79     private MsoNetworkAdapterImpl networkAdapterImpl;
80
81     @Autowired
82     private MsoHeatUtils msoHeatUtils;
83
84     @Autowired
85     private VnfAdapterUtils vnfAdapterUtils;
86
87     @Autowired
88     private AuditMDCSetup mdcSetup;
89
90     public PollService() {
91         super(RetrySequenceLevel.SHORT);
92     }
93
94     public void executeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService) {
95         mdcSetup.setupMDC(externalTask);
96         logger.debug("Starting External Task Poll Service");
97         Map<String, Object> variables = new HashMap<>();
98         MutableBoolean success = new MutableBoolean();
99         String errorMessage = null;
100         Optional<String> response = Optional.empty();
101         boolean isMulticloud = false;
102         try {
103             String xmlRequest = externalTask.getVariable("openstackAdapterTaskRequest");
104             if (xmlRequest != null) {
105                 Optional<String> requestType = findRequestType(xmlRequest);
106                 if ("createVolumeGroupRequest".equals(requestType.get())) {
107                     CreateVolumeGroupRequest req =
108                             JAXB.unmarshal(new StringReader(xmlRequest), CreateVolumeGroupRequest.class);
109                     isMulticloud = vnfAdapterUtils.isMulticloudMode(null, req.getCloudSiteId());
110                     response = determineCreateVolumeGroupStatus(req, externalTask, success, isMulticloud);
111                 } else if ("createVfModuleRequest".equals(requestType.get())) {
112                     CreateVfModuleRequest req =
113                             JAXB.unmarshal(new StringReader(xmlRequest), CreateVfModuleRequest.class);
114                     isMulticloud = vnfAdapterUtils.isMulticloudMode(null, req.getCloudSiteId());
115                     response = determineCreateVfModuleStatus(req, externalTask, success, isMulticloud);
116                 } else if ("deleteVfModuleRequest".equals(requestType.get())) {
117                     logger.debug("Executing External Task Poll Service for Delete Vf Module");
118                     String stackId = externalTask.getVariable("stackId");
119                     DeleteVfModuleRequest req =
120                             JAXB.unmarshal(new StringReader(xmlRequest), DeleteVfModuleRequest.class);
121                     isMulticloud = vnfAdapterUtils.isMulticloudMode(null, req.getCloudSiteId());
122                     if (!isMulticloud) {
123                         int timeoutMinutes = msoHeatUtils.getVfHeatTimeoutValue(req.getModelCustomizationUuid(), false);
124                         StackInfo stack = pollDeleteResource(timeoutMinutes, req.getCloudSiteId(), req.getTenantId(),
125                                 stackId, success);
126                         DeleteVfModuleResponse deleteResponse =
127                                 new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE,
128                                         req.getMessageId(), vnfAdapterImpl.copyStringOutputs(stack.getOutputs()));
129                         response = Optional.of(deleteResponse.toXmlString());
130                     }
131                 } else if ("deleteVolumeGroupRequest".equals(requestType.get())) {
132                     logger.debug("Executing External Task Poll Service for Delete Volume Group");
133                     String stackId = externalTask.getVariable("stackId");
134                     DeleteVolumeGroupRequest req =
135                             JAXB.unmarshal(new StringReader(xmlRequest), DeleteVolumeGroupRequest.class);
136                     isMulticloud = vnfAdapterUtils.isMulticloudMode(null, req.getCloudSiteId());
137                     if (!isMulticloud) {
138                         pollDeleteResource(118, req.getCloudSiteId(), req.getTenantId(), stackId, success);
139                         DeleteVolumeGroupResponse deleteResponse =
140                                 new DeleteVolumeGroupResponse(true, req.getMessageId());
141                         response = Optional.of(deleteResponse.toXmlString());
142                     }
143                 } else if ("createNetworkRequest".equals(requestType.get())) {
144                     CreateNetworkRequest req = JAXB.unmarshal(new StringReader(xmlRequest), CreateNetworkRequest.class);
145                     response = determineCreateNetworkStatus(req, externalTask, success);
146                 } else if ("deleteNetworkRequest".equals(requestType.get())) {
147                     logger.debug("Executing External Task Poll Service for Delete Network");
148                     String stackId = externalTask.getVariable("stackId");
149                     DeleteNetworkRequest req = JAXB.unmarshal(new StringReader(xmlRequest), DeleteNetworkRequest.class);
150                     pollDeleteResource(118, req.getCloudSiteId(), req.getTenantId(), stackId, success);
151                     DeleteNetworkResponse deleteResponse =
152                             new DeleteNetworkResponse(req.getNetworkId(), true, req.getMessageId());
153                     response = Optional.of(deleteResponse.toXmlString());
154                 } else if ("updateNetworkRequest".equals(requestType.get())) {
155                     UpdateNetworkRequest req = JAXB.unmarshal(new StringReader(xmlRequest), UpdateNetworkRequest.class);
156                     pollUpdateResource(req.getCloudSiteId(), req.getTenantId(), externalTask, success);
157                     UpdateNetworkResponse updateResponse =
158                             new UpdateNetworkResponse(req.getNetworkId(), null, null, req.getMessageId());
159                     response = Optional.of(updateResponse.toXmlString());
160                 }
161             }
162         } catch (Exception e) {
163             logger.error("Error during External Task Poll Service", e);
164             errorMessage = e.toString();
165             variables.put("openstackAdapterErrorMessage", errorMessage);
166         }
167
168         if (isMulticloud) {
169             success.setTrue();
170         }
171         if (response.isPresent()) {
172             variables.put("WorkflowResponse", response.get());
173         }
174         variables.put("OpenstackPollSuccess", success.booleanValue());
175         if (success.isTrue()) {
176             externalTaskService.complete(externalTask, variables);
177             logger.debug("The External Task Id: {}  Successful", externalTask.getId());
178         } else {
179             if (externalTask.getRetries() == null) {
180                 logger.debug("The External Task Id: {}  Failed, Setting Retries to Default Start Value: {}",
181                         externalTask.getId(), getRetrySequence().length);
182                 externalTaskService.handleFailure(externalTask, "errorMessage", "errorDetails",
183                         getRetrySequence().length, 10000);
184             } else if (externalTask.getRetries() != null && externalTask.getRetries() - 1 == 0) {
185                 logger.debug("The External Task Id: {}  Failed, All Retries Exhausted", externalTask.getId());
186                 externalTaskService.complete(externalTask, variables);
187             } else {
188                 logger.debug("The External Task Id: {}  Failed, Decrementing Retries: {} , Retry Delay: {}",
189                         externalTask.getId(), externalTask.getRetries() - 1,
190                         calculateRetryDelay(externalTask.getRetries()));
191                 externalTaskService.handleFailure(externalTask, "errorMessage", "errorDetails",
192                         externalTask.getRetries() - 1, calculateRetryDelay(externalTask.getRetries()));
193             }
194         }
195     }
196
197     private Optional<String> determineCreateVolumeGroupStatus(CreateVolumeGroupRequest req, ExternalTask externalTask,
198             MutableBoolean success, boolean isMulticloud) throws MsoException {
199         boolean pollRollbackStatus = externalTask.getVariable("PollRollbackStatus");
200         String stackId = externalTask.getVariable("stackId");
201         if (pollRollbackStatus) {
202             logger.debug("Executing External Task Poll Service for Rollback Volume Group");
203             if (!isMulticloud) {
204                 pollDeleteResource(118, req.getCloudSiteId(), req.getTenantId(), stackId, success);
205             }
206             return Optional.empty();
207         } else {
208             logger.debug("Executing External Task Poll Service for Create Volume Group");
209             Map<String, String> outputs = new HashMap<String, String>();
210             if (!isMulticloud) {
211                 int timeoutMinutes = msoHeatUtils.getVfHeatTimeoutValue(req.getModelCustomizationUuid(), true);
212                 StackInfo stack =
213                         pollCreateResource(timeoutMinutes, req.getCloudSiteId(), req.getTenantId(), stackId, success);
214                 outputs = vnfAdapterImpl.copyStringOutputs(stack.getOutputs());
215             }
216             VolumeGroupRollback rb = new VolumeGroupRollback(req.getVolumeGroupId(), stackId, true, req.getTenantId(),
217                     req.getCloudOwner(), req.getCloudSiteId(), req.getMsoRequest(), req.getMessageId());
218             CreateVolumeGroupResponse createResponse = new CreateVolumeGroupResponse(req.getVolumeGroupId(), stackId,
219                     true, outputs, rb, req.getMessageId());
220             return Optional.of(createResponse.toXmlString());
221         }
222     }
223
224     private Optional<String> determineCreateVfModuleStatus(CreateVfModuleRequest req, ExternalTask externalTask,
225             MutableBoolean success, boolean isMulticloud) throws MsoException {
226         String stackId = externalTask.getVariable("stackId");
227         boolean pollRollbackStatus = externalTask.getVariable("PollRollbackStatus");
228         int timeoutMinutes = msoHeatUtils.getVfHeatTimeoutValue(req.getModelCustomizationUuid(), false);
229         if (pollRollbackStatus) {
230             logger.debug("Executing External Task Poll Service for Rollback Vf Module");
231             if (!isMulticloud) {
232                 pollDeleteResource(timeoutMinutes, req.getCloudSiteId(), req.getTenantId(), stackId, success);
233             }
234             return Optional.empty();
235         } else {
236             logger.debug("Executing External Task Poll Service for Create Vf Module");
237             Map<String, String> outputs = new HashMap<String, String>();
238             if (!isMulticloud) {
239                 StackInfo stack =
240                         pollCreateResource(timeoutMinutes, req.getCloudSiteId(), req.getTenantId(), stackId, success);
241                 outputs = vnfAdapterImpl.copyStringOutputs(stack.getOutputs());
242             }
243             VfModuleRollback modRollback = new VfModuleRollback(buildVnfRollback(req, stackId, isMulticloud),
244                     req.getVfModuleId(), stackId, req.getMessageId());
245             CreateVfModuleResponse createResponse = new CreateVfModuleResponse(req.getVnfId(), req.getVfModuleId(),
246                     stackId, Boolean.TRUE, outputs, modRollback, req.getMessageId());
247             return Optional.of(createResponse.toXmlString());
248         }
249     }
250
251     private Optional<String> determineCreateNetworkStatus(CreateNetworkRequest req, ExternalTask externalTask,
252             MutableBoolean success) throws MsoException {
253         String stackId = externalTask.getVariable("stackId");
254         boolean pollRollbackStatus = externalTask.getVariable("PollRollbackStatus");
255         int timeoutMinutes =
256                 msoHeatUtils.getNetworkHeatTimeoutValue(req.getModelCustomizationUuid(), req.getNetworkType());
257         if (pollRollbackStatus) {
258             logger.debug("Executing External Task Poll Service for Rollback Network");
259             pollDeleteResource(timeoutMinutes, req.getCloudSiteId(), req.getTenantId(), stackId, success);
260             return Optional.empty();
261         } else {
262             logger.debug("Executing External Task Poll Service for Create Network");
263             boolean os3Nw = externalTask.getVariable("os3Nw");
264             StackInfo stack =
265                     pollCreateResource(timeoutMinutes, req.getCloudSiteId(), req.getTenantId(), stackId, success);
266             String networkFqdn = "";
267             String neutronNetworkId = "";
268             Map<String, String> subnetMap = new HashMap<>();
269             if (stack.getOutputs() != null) {
270                 networkFqdn = (String) stack.getOutputs().get("network_fqdn");
271                 neutronNetworkId = (String) stack.getOutputs().get("network_id");
272                 subnetMap = networkAdapterImpl.buildSubnetMap(stack.getOutputs(), req.getSubnets(), os3Nw);
273             }
274             CreateNetworkResponse response = new CreateNetworkResponse(req.getNetworkId(), neutronNetworkId, stackId,
275                     networkFqdn, true, subnetMap, buildNetworkRollback(req, stackId), req.getMessageId());
276             return Optional.of(response.toXmlString());
277
278         }
279     }
280
281     private StackInfo pollCreateResource(int pollingTimeout, String cloudSiteId, String tenantId, String stackId,
282             MutableBoolean success) throws MsoException {
283         Stack currentStack = createCurrentStack(stackId);
284         Stack stack = msoHeatUtils.pollStackForStatus(pollingTimeout, currentStack, "CREATE_IN_PROGRESS", cloudSiteId,
285                 tenantId, false);
286         msoHeatUtils.postProcessStackCreate(stack, false, 0, false, cloudSiteId, tenantId, null);
287         success.setTrue();
288         return new StackInfoMapper(stack).map();
289     }
290
291     private StackInfo pollDeleteResource(int pollingTimeout, String cloudSiteId, String tenantId, String stackId,
292             MutableBoolean success) throws MsoException {
293         Stack currentStack = createCurrentStack(stackId);
294         Stack stack = msoHeatUtils.pollStackForStatus(pollingTimeout, currentStack, "DELETE_IN_PROGRESS", cloudSiteId,
295                 tenantId, true);
296         if (stack != null) { // if stack is null it was not found and no need to do post process
297             msoHeatUtils.postProcessStackDelete(stack);
298         }
299         success.setTrue();
300         return new StackInfoMapper(stack).map();
301     }
302
303     private void pollUpdateResource(String cloudSiteId, String tenantId, ExternalTask externalTask,
304             MutableBoolean success) throws MsoException {
305         Stack currentStack = createCurrentStack(externalTask.getVariable("stackId"));
306         Stack stack =
307                 msoHeatUtils.pollStackForStatus(1, currentStack, "UPDATE_IN_PROGRESS", cloudSiteId, tenantId, false);
308         msoHeatUtils.postProcessStackUpdate(stack);
309         success.setTrue();
310     }
311
312     protected Optional<String> findRequestType(String xmlString) {
313         try {
314             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
315             DocumentBuilder builder = factory.newDocumentBuilder();
316             org.w3c.dom.Document doc;
317             doc = builder.parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));
318             return Optional.of(doc.getDocumentElement().getNodeName());
319         } catch (Exception e) {
320             logger.error("Error Finding Request Type", e);
321             return Optional.empty();
322         }
323     }
324
325     private Stack createCurrentStack(String canonicalStackId) {
326         Stack currentStack = new Stack();
327         String stackName = canonicalStackId;
328         if (canonicalStackId.contains("/")) {
329             String[] stacks = canonicalStackId.split("/");
330             stackName = stacks[0];
331             currentStack.setId(stacks[1]);
332         }
333         currentStack.setStackName(stackName);
334         return currentStack;
335     }
336
337     private VnfRollback buildVnfRollback(CreateVfModuleRequest req, String stackId, boolean isMulticloud) {
338         VnfRollback vfRollback = new VnfRollback();
339         vfRollback.setCloudSiteId(req.getCloudSiteId());
340         vfRollback.setCloudOwner(req.getCloudOwner());
341         vfRollback.setTenantId(req.getTenantId());
342         vfRollback.setMsoRequest(req.getMsoRequest());
343         vfRollback.setRequestType(req.getRequestType());
344         vfRollback.setVolumeGroupHeatStackId(req.getVolumeGroupStackId());
345         vfRollback.setBaseGroupHeatStackId(req.getBaseVfModuleStackId());
346         vfRollback.setIsBase(false);
347         vfRollback.setModelCustomizationUuid(req.getModelCustomizationUuid());
348         vfRollback.setVnfId(stackId);
349         vfRollback.setVnfCreated(true);
350         if (isMulticloud) {
351             vfRollback.setMode("CFY");
352         }
353
354         return vfRollback;
355     }
356
357     private NetworkRollback buildNetworkRollback(CreateNetworkRequest req, String stackId) {
358         NetworkRollback networkRollback = new NetworkRollback();
359         networkRollback.setCloudId(req.getCloudSiteId());
360         networkRollback.setTenantId(req.getTenantId());
361         networkRollback.setMsoRequest(req.getMsoRequest());
362         networkRollback.setModelCustomizationUuid(req.getModelCustomizationUuid());
363         networkRollback.setNetworkStackId(stackId);
364         networkRollback.setNetworkCreated(true);
365         networkRollback.setNetworkType(req.getNetworkType());
366
367         return networkRollback;
368     }
369 }