2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.so.bpmn.infrastructure.scripts
23 import org.apache.commons.lang3.*
24 import org.camunda.bpm.engine.delegate.BpmnError
25 import org.camunda.bpm.engine.delegate.DelegateExecution
26 import org.onap.so.bpmn.common.scripts.AaiUtil
27 import org.onap.so.bpmn.common.scripts.AbstractServiceTaskProcessor
28 import org.onap.so.bpmn.common.scripts.ExceptionUtil
29 import org.onap.so.bpmn.common.scripts.MsoUtils
30 import org.onap.so.bpmn.core.UrnPropertiesReader;
31 import org.onap.so.bpmn.core.WorkflowException
32 import org.onap.so.bpmn.core.json.JsonUtils
33 import org.onap.so.logger.MsoLogger
34 import org.onap.so.rest.APIResponse
35 import org.springframework.web.util.UriUtils
37 class DoDeleteVfModuleVolumeV2 extends AbstractServiceTaskProcessor{
38 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, DoDeleteVfModuleVolumeV2.class);
40 String prefix="DDVMV_"
41 ExceptionUtil exceptionUtil = new ExceptionUtil()
42 XmlParser xmlParser = new XmlParser()
43 JsonUtils jsonUtil = new JsonUtils()
46 public void preProcessRequest(DelegateExecution execution) {
47 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
48 preProcessRequest(execution, isDebugEnabled)
52 * Set default variable values
54 * @param isDebugLogEnabled
56 public void preProcessRequest (DelegateExecution execution, isDebugEnabled) {
61 // failIfNotFound (Optional)
62 // serviceInstanceId (Optional)
65 // vfModuleModelInfo (Optional)
66 // lcpCloudRegionId (Optional) @TODO: this is actually required
67 // tenantId (Optional) @TODO: this is actually required
68 // cloudConfiguration @TODO: temporary solution? this contains lcpCloudregion and tenantId
71 // workflowException @TODO: actual variable name is WorkflowException
75 execution.setVariable('prefix', prefix)
76 execution.setVariable('wasDeleted', 'false')
78 def tenantId = execution.getVariable("tenantId")
79 def cloudSiteId = execution.getVariable("lcpCloudRegionId")
81 // if tenantId or lcpCloudregionId is not passed, get it from cloudRegionConfiguration variable
82 if(!tenantId || !cloudSiteId) {
83 def cloudConfiguration = execution.getVariable("cloudConfiguration")
84 msoLogger.debug("Using cloudConfiguration variable to get tenantId and lcpCloudRegionId - " + cloudConfiguration)
85 tenantId = jsonUtil.getJsonValue(cloudConfiguration, "tenantId")
86 execution.setVariable("tenantId", tenantId)
87 cloudSiteId = jsonUtil.getJsonValue(cloudConfiguration, "lcpCloudRegionId")
88 execution.setVariable("lcpCloudRegionId", cloudSiteId)
94 * Set out 'wasDeleted' variable to 'true'
96 * @param isDebugLogEnabled
98 public void postProcess(DelegateExecution execution, isDebugLogEnabled) {
99 execution.setVariable('wasDeleted', 'true')
104 * Query and set cloud region to use for AAI calls
105 * Output variables: prefix+'aicCloudRegion', prefix+'cloudRegion'
107 * @param isDebugEnabled
109 public void callRESTQueryAAICloudRegion(DelegateExecution execution, isDebugEnabled) {
111 String cloudRegion = execution.getVariable('lcpCloudRegionId')
112 String aai_endpoint = UrnPropertiesReader.getVariable("aai.endpoint",execution)
113 AaiUtil aaiUtil = new AaiUtil(this)
114 String aai_uri = aaiUtil.getCloudInfrastructureCloudRegionUri(execution)
115 String queryCloudRegionRequest = "${aai_endpoint}${aai_uri}/" + cloudRegion
116 msoLogger.debug(queryCloudRegionRequest)
117 msoLogger.debug("AAI query cloud region URI - " + queryCloudRegionRequest)
119 cloudRegion = aaiUtil.getAAICloudReqion(execution, queryCloudRegionRequest, "PO", cloudRegion)
121 if ((cloudRegion != "ERROR")) {
122 if(execution.getVariable(prefix+"queryCloudRegionReturnCode") == "404") {
123 execution.setVariable(prefix+"aicCloudRegion", "AAIAIC25")
126 execution.setVariable(prefix+"aicCloudRegion", cloudRegion)
130 msoLogger.debug("AAI Query Cloud Region Unsuccessful.")
131 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "AAI Query Cloud Region Unsuccessful. Return Code: " + execution.getVariable(prefix+"queryCloudRegionReturnCode"))
137 * Query AAI Volume Group
138 * Output variables: prefix+'queryAAIVolGrpResponse'; prefix+'volumeGroupHeatStackId'
140 * @param isDebugLogEnabled
142 public void callRESTQueryAAIForVolumeGroup(DelegateExecution execution, isDebugLogEnabled) {
144 def tenantId = execution.getVariable('tenantId')
145 def volumeGroupId = execution.getVariable('volumeGroupId')
146 if(volumeGroupId == null) {
147 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, 'volumeGroupId is not provided in the request')
148 throw new Exception('volume-group-id is not provided in the request')
150 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
152 AaiUtil aaiUtil = new AaiUtil(this)
153 String aaiEndpoint = aaiUtil.getCloudInfrastructureCloudRegionEndpoint(execution)
154 String queryAAIVolumeGroupRequest = aaiEndpoint + '/' + URLEncoder.encode(cloudRegion, "UTF-8") + "/volume-groups/volume-group/" + UriUtils.encode(volumeGroupId, "UTF-8")
156 msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest)
157 msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest)
159 APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIVolumeGroupRequest)
161 String returnCode = response.getStatusCode()
162 String aaiResponseAsString = response.getResponseBodyAsString()
164 msoLogger.debug("AAI query volume group by id return code: " + returnCode)
165 msoLogger.debug("AAI query volume group by id response: " + aaiResponseAsString)
166 msoLogger.debug('AAI query volume group by id return code: ' + returnCode)
167 msoLogger.debug('AAI query volume group by id response: ' + aaiResponseAsString)
169 execution.setVariable(prefix+"queryAAIVolGrpResponse", aaiResponseAsString)
171 if (returnCode=='200' || returnCode == '204') {
173 def heatStackId = getNodeTextForce(aaiResponseAsString, 'heat-stack-id')
174 execution.setVariable(prefix+'volumeGroupHeatStackId', heatStackId)
176 msoLogger.debug('Heat stack id from AAI response: ' + heatStackId)
178 if(hasVfModuleRelationship(aaiResponseAsString)){
179 msoLogger.debug('Volume Group ' + volumeGroupId + ' currently in use')
180 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group ${volumeGroupId} currently in use - found vf-module relationship.")
183 def volumeGroupTenantId = getTenantIdFromVolumeGroup(aaiResponseAsString)
184 msoLogger.debug('Tenant ID from AAI response: ' + volumeGroupTenantId)
186 if (volumeGroupTenantId == null) {
187 msoLogger.debug("Could not find Tenant Id element in Volume Group with Volume Group Id ${volumeGroupId}")
188 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id ${volumeGroupId}")
191 if (volumeGroupTenantId != tenantId) {
192 def String errorMessage = 'TenantId ' + tenantId + ' in incoming request does not match Tenant Id ' + volumeGroupTenantId + ' retrieved from AAI for Volume Group Id ' + volumeGroupId
193 msoLogger.debug("Error in DeleteVfModuleVolume: " + errorMessage)
194 exceptionUtil.buildAndThrowWorkflowException(execution, 5000, errorMessage)
196 msoLogger.debug('Received Tenant Id ' + volumeGroupTenantId + ' from AAI for Volume Group with Volume Group Id ' + volumeGroupId )
199 if (returnCode=='404') {
200 msoLogger.debug("Volume Group ${volumeGroupId} not found in AAI")
201 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group ${volumeGroupId} not found in AAI. Response code: 404")
204 WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution)
205 throw new BpmnError("MSOWorkflowException")
211 * Format VNF Adapter subflow request XML
212 * Variables: prefix+'deleteVnfARequest'
214 * @param isDebugLogEnabled
216 public void prepareVnfAdapterDeleteRequest(DelegateExecution execution, isDebugLogEnabled) {
217 def cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
218 def tenantId = execution.getVariable('tenantId') // input parameter (optional) - see preProcessRequest
219 def volumeGroupId = execution.getVariable('volumeGroupId') // input parameter (required)
220 def volumeGroupHeatStackId = execution.getVariable(prefix+'volumeGroupHeatStackId') // from AAI query volume group
221 def requestId = execution.getVariable('msoRequestId') // input parameter (required)
222 def serviceId = execution.getVariable('serviceInstanceId') // imput parameter (optional)
224 def messageId = UUID.randomUUID().toString()
225 def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
226 def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host",execution)
227 if ('true'.equals(useQualifiedHostName)) {
228 notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
231 String vnfAdapterRestRequest = """
232 <deleteVolumeGroupRequest>
233 <cloudSiteId>${MsoUtils.xmlEscape(cloudRegion)}</cloudSiteId>
234 <tenantId>${MsoUtils.xmlEscape(tenantId)}</tenantId>
235 <volumeGroupId>${MsoUtils.xmlEscape(volumeGroupId)}</volumeGroupId>
236 <volumeGroupStackId>${MsoUtils.xmlEscape(volumeGroupHeatStackId)}</volumeGroupStackId>
237 <skipAAI>true</skipAAI>
239 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
240 <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
242 <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
243 <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
244 </deleteVolumeGroupRequest>
246 vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
247 execution.setVariable(prefix+'deleteVnfARequest', vnfAdapterRestRequest)
248 msoLogger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest)
253 * Delete volume group in AAI
255 * @param isDebugEnabled
257 public void callRESTDeleteAAIVolumeGroup(DelegateExecution execution, isDebugEnabled) {
260 String queryAAIVolGrpIdResponse = execution.getVariable(prefix+"queryAAIVolGrpResponse")
261 String groupId = utils.getNodeText(queryAAIVolGrpIdResponse, "volume-group-id")
262 String resourceVersion = utils.getNodeText(queryAAIVolGrpIdResponse, "resource-version")
264 String messageId = UUID.randomUUID().toString()
265 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
267 AaiUtil aaiUtil = new AaiUtil(this)
268 String aaiEndpoint = aaiUtil.getCloudInfrastructureCloudRegionEndpoint(execution)
269 String deleteAAIVolumeGrpIdRequest = aaiEndpoint + '/' + URLEncoder.encode(cloudRegion, "UTF-8") + "/volume-groups/volume-group/" + UriUtils.encode(groupId, "UTF-8")
271 if(resourceVersion !=null){
272 deleteAAIVolumeGrpIdRequest = deleteAAIVolumeGrpIdRequest +'?resource-version=' + UriUtils.encode(resourceVersion, 'UTF-8')
275 msoLogger.debug('Delete AAI volume group : ' + deleteAAIVolumeGrpIdRequest)
276 msoLogger.debug("Delete AAI volume group : " + deleteAAIVolumeGrpIdRequest)
278 APIResponse response = aaiUtil.executeAAIDeleteCall(execution, deleteAAIVolumeGrpIdRequest)
280 String returnCode = response.getStatusCode()
281 String aaiResponseAsString = response.getResponseBodyAsString()
283 msoLogger.debug("AAI delete volume group return code: " + returnCode)
284 msoLogger.debug("AAI delete volume group response: " + aaiResponseAsString)
285 msoLogger.debug("AAI delete volume group return code: " + returnCode)
286 msoLogger.debug("AAI delete volume group response: " + aaiResponseAsString)
288 ExceptionUtil exceptionUtil = new ExceptionUtil()
289 if (returnCode=='200' || (returnCode == '204')) {
290 msoLogger.debug("Volume group $groupId deleted.")
292 if (returnCode=='404') {
293 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume group $groupId not found for delete in AAI Response code: 404")
295 WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution)
296 throw new BpmnError("MSOWorkflowException")
303 * Check if volume group has a relationship to vf-module
304 * @param volumeGroupXml
307 private boolean hasVfModuleRelationship(String volumeGroupXml) {
308 def Node volumeGroupNode = xmlParser.parseText(volumeGroupXml)
309 def Node relationshipList = utils.getChildNode(volumeGroupNode, 'relationship-list')
310 if (relationshipList != null) {
311 def NodeList relationships = utils.getIdenticalChildren(relationshipList, 'relationship')
312 for (Node relationship in relationships) {
313 def Node relatedTo = utils.getChildNode(relationship, 'related-to')
314 if ((relatedTo != null) && (relatedTo.text().equals('vf-module'))) {
315 def Node relatedLink = utils.getChildNode(relationship, 'related-link')
316 if (relatedLink !=null && relatedLink.text() != null){
327 * Extract the Tenant Id from the Volume Group information returned by AAI.
328 * @param volumeGroupXml Volume Group XML returned by AAI.
329 * @return the Tenant Id extracted from the Volume Group information. 'null' is returned if
330 * the Tenant Id is missing or could not otherwise be extracted.
332 private String getTenantIdFromVolumeGroup(String volumeGroupXml) {
333 def Node volumeGroupNode = xmlParser.parseText(volumeGroupXml)
334 def Node relationshipList = utils.getChildNode(volumeGroupNode, 'relationship-list')
335 if (relationshipList != null) {
336 def NodeList relationships = utils.getIdenticalChildren(relationshipList, 'relationship')
337 for (Node relationship in relationships) {
338 def Node relatedTo = utils.getChildNode(relationship, 'related-to')
339 if ((relatedTo != null) && (relatedTo.text().equals('tenant'))) {
340 def NodeList relationshipDataList = utils.getIdenticalChildren(relationship, 'relationship-data')
341 for (Node relationshipData in relationshipDataList) {
342 def Node relationshipKey = utils.getChildNode(relationshipData, 'relationship-key')
343 if ((relationshipKey != null) && (relationshipKey.text().equals('tenant.tenant-id'))) {
344 def Node relationshipValue = utils.getChildNode(relationshipData, 'relationship-value')
345 if (relationshipValue != null) {
346 return relationshipValue.text()