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