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.client.aai.entities.uri.AAIResourceUri
34 import org.onap.so.client.aai.entities.uri.AAIUriFactory
35 import org.onap.so.client.aai.AAIObjectType
36 import org.onap.so.constants.Defaults
37 import org.onap.so.logger.MsoLogger
38 import org.onap.so.rest.APIResponse
39 import org.springframework.web.util.UriUtils
41 class DoDeleteVfModuleVolumeV2 extends AbstractServiceTaskProcessor{
42 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, DoDeleteVfModuleVolumeV2.class);
44 String prefix="DDVMV_"
45 ExceptionUtil exceptionUtil = new ExceptionUtil()
46 XmlParser xmlParser = new XmlParser()
47 JsonUtils jsonUtil = new JsonUtils()
50 public void preProcessRequest(DelegateExecution execution) {
51 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
52 preProcessRequest(execution, isDebugEnabled)
56 * Set default variable values
58 * @param isDebugLogEnabled
60 public void preProcessRequest (DelegateExecution execution, isDebugEnabled) {
65 // failIfNotFound (Optional)
66 // serviceInstanceId (Optional)
69 // vfModuleModelInfo (Optional)
70 // lcpCloudRegionId (Optional) @TODO: this is actually required
71 // tenantId (Optional) @TODO: this is actually required
72 // cloudConfiguration @TODO: temporary solution? this contains lcpCloudregion and tenantId
75 // workflowException @TODO: actual variable name is WorkflowException
79 execution.setVariable('prefix', prefix)
80 execution.setVariable('wasDeleted', 'false')
82 def tenantId = execution.getVariable("tenantId")
83 def cloudSiteId = execution.getVariable("lcpCloudRegionId")
85 // if tenantId or lcpCloudregionId is not passed, get it from cloudRegionConfiguration variable
86 if(!tenantId || !cloudSiteId) {
87 def cloudConfiguration = execution.getVariable("cloudConfiguration")
88 msoLogger.debug("Using cloudConfiguration variable to get tenantId and lcpCloudRegionId - " + cloudConfiguration)
89 tenantId = jsonUtil.getJsonValue(cloudConfiguration, "tenantId")
90 execution.setVariable("tenantId", tenantId)
91 cloudSiteId = jsonUtil.getJsonValue(cloudConfiguration, "lcpCloudRegionId")
92 execution.setVariable("lcpCloudRegionId", cloudSiteId)
93 cloudOwner = jsonUtil.getJsonValue(cloudConfiguration, "cloudOwner")
94 execution.setVariable("cloudOwner", cloudOwner)
100 * Set out 'wasDeleted' variable to 'true'
102 * @param isDebugLogEnabled
104 public void postProcess(DelegateExecution execution, isDebugLogEnabled) {
105 execution.setVariable('wasDeleted', 'true')
110 * Query and set cloud region to use for AAI calls
111 * Output variables: prefix+'aicCloudRegion', prefix+'cloudRegion'
113 * @param isDebugEnabled
115 public void callRESTQueryAAICloudRegion(DelegateExecution execution, isDebugEnabled) {
117 String cloudRegion = execution.getVariable('lcpCloudRegionId')
118 AaiUtil aaiUtil = new AaiUtil(this)
120 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.CLOUD_REGION, Defaults.CLOUD_OWNER.toString(), cloudRegion)
121 def queryCloudRegionRequest = aaiUtil.createAaiUri(uri)
123 cloudRegion = aaiUtil.getAAICloudReqion(execution, queryCloudRegionRequest, "PO", cloudRegion)
125 if ((cloudRegion != "ERROR")) {
126 if(execution.getVariable(prefix+"queryCloudRegionReturnCode") == "404") {
127 execution.setVariable(prefix+"aicCloudRegion", "AAIAIC25")
130 execution.setVariable(prefix+"aicCloudRegion", cloudRegion)
134 msoLogger.debug("AAI Query Cloud Region Unsuccessful.")
135 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "AAI Query Cloud Region Unsuccessful. Return Code: " + execution.getVariable(prefix+"queryCloudRegionReturnCode"))
141 * Query AAI Volume Group
142 * Output variables: prefix+'queryAAIVolGrpResponse'; prefix+'volumeGroupHeatStackId'
144 * @param isDebugLogEnabled
146 public void callRESTQueryAAIForVolumeGroup(DelegateExecution execution, isDebugLogEnabled) {
148 def tenantId = execution.getVariable('tenantId')
149 def volumeGroupId = execution.getVariable('volumeGroupId')
150 if(volumeGroupId == null) {
151 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, 'volumeGroupId is not provided in the request')
152 throw new Exception('volume-group-id is not provided in the request')
154 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
156 AaiUtil aaiUtil = new AaiUtil(this)
158 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(), cloudRegion, volumeGroupId)
159 def queryAAIVolumeGroupRequest = aaiUtil.createAaiUri(uri)
161 msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest)
162 msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest)
164 APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIVolumeGroupRequest)
166 String returnCode = response.getStatusCode()
167 String aaiResponseAsString = response.getResponseBodyAsString()
169 msoLogger.debug("AAI query volume group by id return code: " + returnCode)
170 msoLogger.debug("AAI query volume group by id response: " + aaiResponseAsString)
171 msoLogger.debug('AAI query volume group by id return code: ' + returnCode)
172 msoLogger.debug('AAI query volume group by id response: ' + aaiResponseAsString)
174 execution.setVariable(prefix+"queryAAIVolGrpResponse", aaiResponseAsString)
176 if (returnCode=='200' || returnCode == '204') {
178 def heatStackId = getNodeTextForce(aaiResponseAsString, 'heat-stack-id')
179 execution.setVariable(prefix+'volumeGroupHeatStackId', heatStackId)
181 msoLogger.debug('Heat stack id from AAI response: ' + heatStackId)
183 if(hasVfModuleRelationship(aaiResponseAsString)){
184 msoLogger.debug('Volume Group ' + volumeGroupId + ' currently in use')
185 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group ${volumeGroupId} currently in use - found vf-module relationship.")
188 def volumeGroupTenantId = getTenantIdFromVolumeGroup(aaiResponseAsString)
189 msoLogger.debug('Tenant ID from AAI response: ' + volumeGroupTenantId)
191 if (volumeGroupTenantId == null) {
192 msoLogger.debug("Could not find Tenant Id element in Volume Group with Volume Group Id ${volumeGroupId}")
193 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id ${volumeGroupId}")
196 if (volumeGroupTenantId != tenantId) {
197 def String errorMessage = 'TenantId ' + tenantId + ' in incoming request does not match Tenant Id ' + volumeGroupTenantId + ' retrieved from AAI for Volume Group Id ' + volumeGroupId
198 msoLogger.debug("Error in DeleteVfModuleVolume: " + errorMessage)
199 exceptionUtil.buildAndThrowWorkflowException(execution, 5000, errorMessage)
201 msoLogger.debug('Received Tenant Id ' + volumeGroupTenantId + ' from AAI for Volume Group with Volume Group Id ' + volumeGroupId )
204 if (returnCode=='404') {
205 msoLogger.debug("Volume Group ${volumeGroupId} not found in AAI")
206 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group ${volumeGroupId} not found in AAI. Response code: 404")
209 WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution)
210 throw new BpmnError("MSOWorkflowException")
216 * Format VNF Adapter subflow request XML
217 * Variables: prefix+'deleteVnfARequest'
219 * @param isDebugLogEnabled
221 public void prepareVnfAdapterDeleteRequest(DelegateExecution execution, isDebugLogEnabled) {
222 def cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
223 def tenantId = execution.getVariable('tenantId') // input parameter (optional) - see preProcessRequest
224 def volumeGroupId = execution.getVariable('volumeGroupId') // input parameter (required)
225 def volumeGroupHeatStackId = execution.getVariable(prefix+'volumeGroupHeatStackId') // from AAI query volume group
226 def requestId = execution.getVariable('msoRequestId') // input parameter (required)
227 def serviceId = execution.getVariable('serviceInstanceId') // imput parameter (optional)
229 def messageId = UUID.randomUUID().toString()
230 def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
231 def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host",execution)
232 if ('true'.equals(useQualifiedHostName)) {
233 notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
236 String vnfAdapterRestRequest = """
237 <deleteVolumeGroupRequest>
238 <cloudSiteId>${MsoUtils.xmlEscape(cloudRegion)}</cloudSiteId>
239 <tenantId>${MsoUtils.xmlEscape(tenantId)}</tenantId>
240 <volumeGroupId>${MsoUtils.xmlEscape(volumeGroupId)}</volumeGroupId>
241 <volumeGroupStackId>${MsoUtils.xmlEscape(volumeGroupHeatStackId)}</volumeGroupStackId>
242 <skipAAI>true</skipAAI>
244 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
245 <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
247 <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
248 <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
249 </deleteVolumeGroupRequest>
251 vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
252 execution.setVariable(prefix+'deleteVnfARequest', vnfAdapterRestRequest)
253 msoLogger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest)
258 * Delete volume group in AAI
260 * @param isDebugEnabled
262 public void callRESTDeleteAAIVolumeGroup(DelegateExecution execution, isDebugEnabled) {
265 String queryAAIVolGrpIdResponse = execution.getVariable(prefix+"queryAAIVolGrpResponse")
266 String groupId = utils.getNodeText(queryAAIVolGrpIdResponse, "volume-group-id")
267 String resourceVersion = utils.getNodeText(queryAAIVolGrpIdResponse, "resource-version")
269 String messageId = UUID.randomUUID().toString()
270 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
272 AaiUtil aaiUtil = new AaiUtil(this)
274 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(), cloudRegion, groupId).resourceVersion(resourceVersion)
275 def deleteAAIVolumeGrpIdRequest = aaiUtil.createAaiUri(uri)
277 msoLogger.debug('Delete AAI volume group : ' + deleteAAIVolumeGrpIdRequest)
278 msoLogger.debug("Delete AAI volume group : " + deleteAAIVolumeGrpIdRequest)
280 APIResponse response = aaiUtil.executeAAIDeleteCall(execution, deleteAAIVolumeGrpIdRequest)
282 String returnCode = response.getStatusCode()
283 String aaiResponseAsString = response.getResponseBodyAsString()
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()