2 * ============LICENSE_START=======================================================
\r
4 * ================================================================================
\r
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * ================================================================================
\r
7 * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * you may not use this file except in compliance with the License.
\r
9 * You may obtain a copy of the License at
\r
11 * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * Unless required by applicable law or agreed to in writing, software
\r
14 * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * See the License for the specific language governing permissions and
\r
17 * limitations under the License.
\r
18 * ============LICENSE_END=========================================================
\r
21 package org.openecomp.mso.bpmn.infrastructure.scripts
\r
23 import groovy.json.JsonSlurper
\r
24 import groovy.util.XmlParser;
\r
26 import java.util.concurrent.ExecutionException;
\r
28 import org.springframework.web.util.UriUtils
\r
29 import org.camunda.bpm.engine.delegate.BpmnError
\r
30 import org.camunda.bpm.engine.runtime.Execution
\r
31 import org.openecomp.mso.bpmn.common.scripts.AaiUtil
\r
32 import org.openecomp.mso.bpmn.common.scripts.AbstractServiceTaskProcessor
\r
33 import org.openecomp.mso.bpmn.common.scripts.ExceptionUtil
\r
34 import org.openecomp.mso.bpmn.core.WorkflowException
\r
35 import org.openecomp.mso.bpmn.core.json.JsonUtils
\r
36 import org.openecomp.mso.rest.APIResponse
\r
37 import org.apache.commons.lang3.*
\r
39 class DoDeleteVfModuleVolumeV2 extends AbstractServiceTaskProcessor {
\r
41 String prefix="DDVMV_"
\r
42 ExceptionUtil exceptionUtil = new ExceptionUtil()
\r
43 XmlParser xmlParser = new XmlParser()
\r
44 JsonUtils jsonUtil = new JsonUtils()
\r
47 public void preProcessRequest(Execution execution) {
\r
48 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
\r
49 preProcessRequest(execution, isDebugEnabled)
\r
53 * Set default variable values
\r
55 * @param isDebugLogEnabled
\r
57 public void preProcessRequest (Execution execution, isDebugEnabled) {
\r
61 // isDebugLogEnabled
\r
62 // failIfNotFound (Optional)
\r
63 // serviceInstanceId (Optional)
\r
66 // vfModuleModelInfo (Optional)
\r
67 // lcpCloudRegionId (Optional) @TODO: this is actually required
\r
68 // tenantId (Optional) @TODO: this is actually required
\r
69 // cloudConfiguration @TODO: temporary solution? this contains lcpCloudregion and tenantId
\r
72 // workflowException @TODO: actual variable name is WorkflowException
\r
76 execution.setVariable('prefix', prefix)
\r
77 execution.setVariable('wasDeleted', 'false')
\r
79 def tenantId = execution.getVariable("tenantId")
\r
80 def cloudSiteId = execution.getVariable("lcpCloudRegionId")
\r
82 // if tenantId or lcpCloudregionId is not passed, get it from cloudRegionConfiguration variable
\r
83 if(!tenantId || !cloudSiteId) {
\r
84 def cloudConfiguration = execution.getVariable("cloudConfiguration")
\r
85 utils.log("DEBUG", "Using cloudConfiguration variable to get tenantId and lcpCloudRegionId - " + cloudConfiguration, isDebugEnabled)
\r
86 tenantId = jsonUtil.getJsonValue(cloudConfiguration, "tenantId")
\r
87 execution.setVariable("tenantId", tenantId)
\r
88 cloudSiteId = jsonUtil.getJsonValue(cloudConfiguration, "lcpCloudRegionId")
\r
89 execution.setVariable("lcpCloudRegionId", cloudSiteId)
\r
95 * Set out 'wasDeleted' variable to 'true'
\r
97 * @param isDebugLogEnabled
\r
99 public void postProcess(Execution execution, isDebugLogEnabled) {
\r
100 execution.setVariable('wasDeleted', 'true')
\r
105 * Query and set cloud region to use for AAI calls
\r
106 * Output variables: prefix+'aicCloudRegion', prefix+'cloudRegion'
\r
108 * @param isDebugEnabled
\r
110 public void callRESTQueryAAICloudRegion(Execution execution, isDebugEnabled) {
\r
112 String cloudRegion = execution.getVariable('lcpCloudRegionId')
\r
113 String aai_endpoint = execution.getVariable("URN_aai_endpoint")
\r
114 AaiUtil aaiUtil = new AaiUtil(this)
\r
115 String aai_uri = aaiUtil.getCloudInfrastructureCloudRegionUri(execution)
\r
116 String queryCloudRegionRequest = "${aai_endpoint}${aai_uri}/" + cloudRegion
\r
117 utils.logAudit(queryCloudRegionRequest)
\r
118 utils.log("DEBUG", "AAI query cloud region URI - " + queryCloudRegionRequest, isDebugEnabled)
\r
120 cloudRegion = aaiUtil.getAAICloudReqion(execution, queryCloudRegionRequest, "PO", cloudRegion)
\r
122 if ((cloudRegion != "ERROR")) {
\r
123 if(execution.getVariable(prefix+"queryCloudRegionReturnCode") == "404") {
\r
124 execution.setVariable(prefix+"aicCloudRegion", "AAIAIC25")
\r
127 execution.setVariable(prefix+"aicCloudRegion", cloudRegion)
\r
131 utils.log("DEBUG", "AAI Query Cloud Region Unsuccessful.", isDebugEnabled)
\r
132 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "AAI Query Cloud Region Unsuccessful. Return Code: " + execution.getVariable(prefix+"queryCloudRegionReturnCode"))
\r
138 * Query AAI Volume Group
\r
139 * Output variables: prefix+'queryAAIVolGrpResponse'; prefix+'volumeGroupHeatStackId'
\r
141 * @param isDebugLogEnabled
\r
143 public void callRESTQueryAAIForVolumeGroup(Execution execution, isDebugLogEnabled) {
\r
145 def tenantId = execution.getVariable('tenantId')
\r
146 def volumeGroupId = execution.getVariable('volumeGroupId')
\r
147 if(volumeGroupId == null) {
\r
148 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, 'volumeGroupId is not provided in the request')
\r
149 throw new Exception('volume-group-id is not provided in the request')
\r
151 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
\r
153 AaiUtil aaiUtil = new AaiUtil(this)
\r
154 String aaiEndpoint = aaiUtil.getCloudInfrastructureCloudRegionEndpoint(execution)
\r
155 String queryAAIVolumeGroupRequest = aaiEndpoint + '/' + URLEncoder.encode(cloudRegion, "UTF-8") + "/volume-groups/volume-group/" + UriUtils.encode(volumeGroupId, "UTF-8")
\r
157 utils.logAudit('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest)
\r
158 logDebug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest, isDebugLogEnabled)
\r
160 APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIVolumeGroupRequest)
\r
162 String returnCode = response.getStatusCode()
\r
163 String aaiResponseAsString = response.getResponseBodyAsString()
\r
164 aaiResponseAsString = StringEscapeUtils.unescapeXml(aaiResponseAsString)
\r
166 utils.logAudit("AAI query volume group by id return code: " + returnCode)
\r
167 utils.logAudit("AAI query volume group by id response: " + aaiResponseAsString)
\r
168 logDebug('AAI query volume group by id return code: ' + returnCode, isDebugLogEnabled)
\r
169 logDebug('AAI query volume group by id response: ' + aaiResponseAsString, isDebugLogEnabled)
\r
171 execution.setVariable(prefix+"queryAAIVolGrpResponse", aaiResponseAsString)
\r
173 if (returnCode=='200' || returnCode == '204') {
\r
175 def heatStackId = getNodeTextForce(aaiResponseAsString, 'heat-stack-id')
\r
176 execution.setVariable(prefix+'volumeGroupHeatStackId', heatStackId)
\r
178 logDebug('Heat stack id from AAI response: ' + heatStackId, isDebugLogEnabled)
\r
180 if(hasVfModuleRelationship(aaiResponseAsString)){
\r
181 utils.log("DEBUG", 'Volume Group ' + volumeGroupId + ' currently in use', isDebugLogEnabled)
\r
182 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group ${volumeGroupId} currently in use - found vf-module relationship.")
\r
185 def volumeGroupTenantId = getTenantIdFromVolumeGroup(aaiResponseAsString)
\r
186 logDebug('Tenant ID from AAI response: ' + volumeGroupTenantId, isDebugLogEnabled)
\r
188 if (volumeGroupTenantId == null) {
\r
189 utils.log("DEBUG", "Could not find Tenant Id element in Volume Group with Volume Group Id ${volumeGroupId}", isDebugLogEnabled)
\r
190 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id ${volumeGroupId}")
\r
193 if (volumeGroupTenantId != tenantId) {
\r
194 def String errorMessage = 'TenantId ' + tenantId + ' in incoming request does not match Tenant Id ' + volumeGroupTenantId + ' retrieved from AAI for Volume Group Id ' + volumeGroupId
\r
195 utils.log("DEBUG", "Error in DeleteVfModuleVolume: " + errorMessage, isDebugLogEnabled)
\r
196 exceptionUtil.buildAndThrowWorkflowException(execution, 5000, errorMessage)
\r
198 logDebug('Received Tenant Id ' + volumeGroupTenantId + ' from AAI for Volume Group with Volume Group Id ' + volumeGroupId , isDebugLogEnabled)
\r
201 if (returnCode=='404') {
\r
202 utils.log("DEBUG", "Volume Group ${volumeGroupId} not found in AAI", isDebugLogEnabled)
\r
203 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group ${volumeGroupId} not found in AAI. Response code: 404")
\r
206 WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution)
\r
207 throw new BpmnError("MSOWorkflowException")
\r
213 * Format VNF Adapter subflow request XML
\r
214 * Variables: prefix+'deleteVnfARequest'
\r
216 * @param isDebugLogEnabled
\r
218 public void prepareVnfAdapterDeleteRequest(Execution execution, isDebugLogEnabled) {
\r
219 def cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
\r
220 def tenantId = execution.getVariable('tenantId') // input parameter (optional) - see preProcessRequest
\r
221 def volumeGroupId = execution.getVariable('volumeGroupId') // input parameter (required)
\r
222 def volumeGroupHeatStackId = execution.getVariable(prefix+'volumeGroupHeatStackId') // from AAI query volume group
\r
223 def requestId = execution.getVariable('msoRequestId') // input parameter (required)
\r
224 def serviceId = execution.getVariable('serviceInstanceId') // imput parameter (optional)
\r
226 def messageId = UUID.randomUUID().toString()
\r
227 def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
\r
228 def useQualifiedHostName = execution.getVariable("URN_mso_use_qualified_host")
\r
229 if ('true'.equals(useQualifiedHostName)) {
\r
230 notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
\r
233 String vnfAdapterRestRequest = """
\r
234 <deleteVolumeGroupRequest>
\r
235 <cloudSiteId>${cloudRegion}</cloudSiteId>
\r
236 <tenantId>${tenantId}</tenantId>
\r
237 <volumeGroupId>${volumeGroupId}</volumeGroupId>
\r
238 <volumeGroupStackId>${volumeGroupHeatStackId}</volumeGroupStackId>
\r
239 <skipAAI>true</skipAAI>
\r
241 <requestId>${requestId}</requestId>
\r
242 <serviceInstanceId>${serviceId}</serviceInstanceId>
\r
244 <messageId>${messageId}</messageId>
\r
245 <notificationUrl>${notificationUrl}</notificationUrl>
\r
246 </deleteVolumeGroupRequest>
\r
248 vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
\r
249 execution.setVariable(prefix+'deleteVnfARequest', vnfAdapterRestRequest)
\r
250 logDebug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest, isDebugLogEnabled)
\r
255 * Delete volume group in AAI
\r
257 * @param isDebugEnabled
\r
259 public void callRESTDeleteAAIVolumeGroup(Execution execution, isDebugEnabled) {
\r
262 String queryAAIVolGrpIdResponse = execution.getVariable(prefix+"queryAAIVolGrpResponse")
\r
263 String groupId = utils.getNodeText(queryAAIVolGrpIdResponse, "volume-group-id")
\r
264 String resourceVersion = utils.getNodeText(queryAAIVolGrpIdResponse, "resource-version")
\r
266 String messageId = UUID.randomUUID().toString()
\r
267 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
\r
269 AaiUtil aaiUtil = new AaiUtil(this)
\r
270 String aaiEndpoint = aaiUtil.getCloudInfrastructureCloudRegionEndpoint(execution)
\r
271 String deleteAAIVolumeGrpIdRequest = aaiEndpoint + '/' + URLEncoder.encode(cloudRegion, "UTF-8") + "/volume-groups/volume-group/" + UriUtils.encode(groupId, "UTF-8")
\r
273 if(resourceVersion !=null){
\r
274 deleteAAIVolumeGrpIdRequest = deleteAAIVolumeGrpIdRequest +'?resource-version=' + UriUtils.encode(resourceVersion, 'UTF-8')
\r
277 utils.logAudit('Delete AAI volume group : ' + deleteAAIVolumeGrpIdRequest)
\r
278 utils.log("DEBUG", "Delete AAI volume group : " + deleteAAIVolumeGrpIdRequest, isDebugEnabled)
\r
280 APIResponse response = aaiUtil.executeAAIDeleteCall(execution, deleteAAIVolumeGrpIdRequest)
\r
282 String returnCode = response.getStatusCode()
\r
283 String aaiResponseAsString = response.getResponseBodyAsString()
\r
284 aaiResponseAsString = StringEscapeUtils.unescapeXml(aaiResponseAsString)
\r
286 utils.logAudit("AAI delete volume group return code: " + returnCode)
\r
287 utils.logAudit("AAI delete volume group response: " + aaiResponseAsString)
\r
288 utils.log("DEBUG", "AAI delete volume group return code: " + returnCode, isDebugEnabled)
\r
289 utils.log("DEBUG", "AAI delete volume group response: " + aaiResponseAsString, isDebugEnabled)
\r
291 ExceptionUtil exceptionUtil = new ExceptionUtil()
\r
292 if (returnCode=='200' || (returnCode == '204')) {
\r
293 utils.log("DEBUG", "Volume group $groupId deleted.", isDebugEnabled)
\r
295 if (returnCode=='404') {
\r
296 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume group $groupId not found for delete in AAI Response code: 404")
\r
298 WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution)
\r
299 throw new BpmnError("MSOWorkflowException")
\r
306 * Check if volume group has a relationship to vf-module
\r
307 * @param volumeGroupXml
\r
310 private boolean hasVfModuleRelationship(String volumeGroupXml) {
\r
311 def Node volumeGroupNode = xmlParser.parseText(volumeGroupXml)
\r
312 def Node relationshipList = utils.getChildNode(volumeGroupNode, 'relationship-list')
\r
313 if (relationshipList != null) {
\r
314 def NodeList relationships = utils.getIdenticalChildren(relationshipList, 'relationship')
\r
315 for (Node relationship in relationships) {
\r
316 def Node relatedTo = utils.getChildNode(relationship, 'related-to')
\r
317 if ((relatedTo != null) && (relatedTo.text().equals('vf-module'))) {
\r
318 def Node relatedLink = utils.getChildNode(relationship, 'related-link')
\r
319 if (relatedLink !=null && relatedLink.text() != null){
\r
330 * Extract the Tenant Id from the Volume Group information returned by AAI.
\r
331 * @param volumeGroupXml Volume Group XML returned by AAI.
\r
332 * @return the Tenant Id extracted from the Volume Group information. 'null' is returned if
\r
333 * the Tenant Id is missing or could not otherwise be extracted.
\r
335 private String getTenantIdFromVolumeGroup(String volumeGroupXml) {
\r
336 def Node volumeGroupNode = xmlParser.parseText(volumeGroupXml)
\r
337 def Node relationshipList = utils.getChildNode(volumeGroupNode, 'relationship-list')
\r
338 if (relationshipList != null) {
\r
339 def NodeList relationships = utils.getIdenticalChildren(relationshipList, 'relationship')
\r
340 for (Node relationship in relationships) {
\r
341 def Node relatedTo = utils.getChildNode(relationship, 'related-to')
\r
342 if ((relatedTo != null) && (relatedTo.text().equals('tenant'))) {
\r
343 def NodeList relationshipDataList = utils.getIdenticalChildren(relationship, 'relationship-data')
\r
344 for (Node relationshipData in relationshipDataList) {
\r
345 def Node relationshipKey = utils.getChildNode(relationshipData, 'relationship-key')
\r
346 if ((relationshipKey != null) && (relationshipKey.text().equals('tenant.tenant-id'))) {
\r
347 def Node relationshipValue = utils.getChildNode(relationshipData, 'relationship-value')
\r
348 if (relationshipValue != null) {
\r
349 return relationshipValue.text()
\r