73fd78f0c0e74a0f67cc4ffb839ffdd5ee88eda3
[so.git] / bpmn / so-bpmn-infrastructure-common / src / main / groovy / org / onap / so / bpmn / infrastructure / scripts / DoDeleteVfModuleVolumeV2.groovy
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.so.bpmn.infrastructure.scripts
22
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
40
41 class DoDeleteVfModuleVolumeV2 extends AbstractServiceTaskProcessor{
42         private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, DoDeleteVfModuleVolumeV2.class);
43
44         String prefix="DDVMV_"
45         ExceptionUtil exceptionUtil = new ExceptionUtil()
46         XmlParser xmlParser = new XmlParser()
47         JsonUtils jsonUtil = new JsonUtils()
48
49         @Override
50         public void preProcessRequest(DelegateExecution execution) {
51                 def isDebugEnabled=execution.getVariable("isDebugLogEnabled")
52                 preProcessRequest(execution, isDebugEnabled)
53         }
54
55         /**
56          * Set default variable values
57          * @param execution
58          * @param isDebugLogEnabled
59          */
60         public void preProcessRequest (DelegateExecution execution, isDebugEnabled) {
61
62                 //Input:
63                 //  msoRequestId
64                 //  isDebugLogEnabled
65                 //  failIfNotFound (Optional)
66                 //  serviceInstanceId (Optional)
67                 //  vnfId (Optional)
68                 //  volumeGroupId
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
73                 //
74                 //Output:
75                 //  workflowException                                   @TODO: actual variable name is WorkflowException
76                 //  rolledBack
77                 //  wasDeleted
78
79                 execution.setVariable('prefix', prefix)
80                 execution.setVariable('wasDeleted', 'false')
81
82                 def tenantId = execution.getVariable("tenantId")
83                 def cloudSiteId = execution.getVariable("lcpCloudRegionId")
84
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)
95                 }
96         }
97
98
99         /**
100          * Set out 'wasDeleted' variable to 'true'
101          * @param execution
102          * @param isDebugLogEnabled
103          */
104         public void postProcess(DelegateExecution execution, isDebugLogEnabled) {
105                 execution.setVariable('wasDeleted', 'true')
106         }
107
108
109         /**
110          * Query and set cloud region to use for AAI calls
111          * Output variables: prefix+'aicCloudRegion', prefix+'cloudRegion'
112          * @param execution
113          * @param isDebugEnabled
114          */
115         public void callRESTQueryAAICloudRegion(DelegateExecution execution, isDebugEnabled) {
116
117                 String cloudRegion = execution.getVariable('lcpCloudRegionId')
118                 AaiUtil aaiUtil = new AaiUtil(this)
119
120                 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.CLOUD_REGION, Defaults.CLOUD_OWNER.toString(), cloudRegion)
121                 def queryCloudRegionRequest = aaiUtil.createAaiUri(uri)
122
123                 cloudRegion = aaiUtil.getAAICloudReqion(execution,  queryCloudRegionRequest, "PO", cloudRegion)
124
125                 if ((cloudRegion != "ERROR")) {
126                         if(execution.getVariable(prefix+"queryCloudRegionReturnCode") == "404") {
127                                 execution.setVariable(prefix+"aicCloudRegion", "AAIAIC25")
128                         }
129                         else{
130                                 execution.setVariable(prefix+"aicCloudRegion", cloudRegion)
131                         }
132                 }
133                 else {
134                         msoLogger.debug("AAI Query Cloud Region Unsuccessful.")
135                         exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "AAI Query Cloud Region Unsuccessful. Return Code: " + execution.getVariable(prefix+"queryCloudRegionReturnCode"))
136                 }
137         }
138
139
140         /**
141          * Query AAI Volume Group
142          * Output variables: prefix+'queryAAIVolGrpResponse'; prefix+'volumeGroupHeatStackId'
143          * @param execution
144          * @param isDebugLogEnabled
145          */
146         public void callRESTQueryAAIForVolumeGroup(DelegateExecution execution, isDebugLogEnabled) {
147
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')
153                 }
154                 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
155
156                 AaiUtil aaiUtil = new AaiUtil(this)
157
158                 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(), cloudRegion, volumeGroupId)
159                 def queryAAIVolumeGroupRequest = aaiUtil.createAaiUri(uri)
160
161                 msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest)
162                 msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest)
163
164                 APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIVolumeGroupRequest)
165
166                 String returnCode = response.getStatusCode()
167                 String aaiResponseAsString = response.getResponseBodyAsString()
168
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)
173
174                 execution.setVariable(prefix+"queryAAIVolGrpResponse", aaiResponseAsString)
175
176                 if (returnCode=='200' || returnCode == '204') {
177
178                         def heatStackId = getNodeTextForce(aaiResponseAsString, 'heat-stack-id')
179                         execution.setVariable(prefix+'volumeGroupHeatStackId', heatStackId)
180
181                         msoLogger.debug('Heat stack id from AAI response: ' + heatStackId)
182
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.")
186                         }
187
188                         def volumeGroupTenantId = getTenantIdFromVolumeGroup(aaiResponseAsString)
189                         msoLogger.debug('Tenant ID from AAI response: ' + volumeGroupTenantId)
190
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}")
194                         }
195
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)
200                         }
201                         msoLogger.debug('Received Tenant Id ' + volumeGroupTenantId + ' from AAI for Volume Group with Volume Group Id ' + volumeGroupId )
202                 }
203                 else {
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")
207                         }
208                         else {
209                                 WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution)
210                                 throw new BpmnError("MSOWorkflowException")
211                         }
212                 }
213         }
214
215         /**
216          * Format VNF Adapter subflow request XML
217          * Variables: prefix+'deleteVnfARequest'
218          * @param execution
219          * @param isDebugLogEnabled
220          */
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)
228
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)
234                 }
235
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>
243                             <msoRequest>
244                                 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
245                                 <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
246                             </msoRequest>
247                             <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
248                             <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
249                         </deleteVolumeGroupRequest>
250                 """
251                 vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
252                 execution.setVariable(prefix+'deleteVnfARequest', vnfAdapterRestRequest)
253                 msoLogger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest)
254         }
255
256
257         /**
258          * Delete volume group in AAI
259          * @param execution
260          * @param isDebugEnabled
261          */
262         public void callRESTDeleteAAIVolumeGroup(DelegateExecution execution, isDebugEnabled) {
263
264                 // get variables
265                 String queryAAIVolGrpIdResponse = execution.getVariable(prefix+"queryAAIVolGrpResponse")
266                 String groupId = utils.getNodeText(queryAAIVolGrpIdResponse, "volume-group-id")
267                 String resourceVersion = utils.getNodeText(queryAAIVolGrpIdResponse, "resource-version")
268
269                 String messageId = UUID.randomUUID().toString()
270                 String cloudRegion = execution.getVariable(prefix+'aicCloudRegion')
271
272                 AaiUtil aaiUtil = new AaiUtil(this)
273
274                 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(), cloudRegion, groupId).resourceVersion(resourceVersion)
275                 def deleteAAIVolumeGrpIdRequest = aaiUtil.createAaiUri(uri)
276
277                 msoLogger.debug('Delete AAI volume group : ' + deleteAAIVolumeGrpIdRequest)
278                 msoLogger.debug("Delete AAI volume group : " + deleteAAIVolumeGrpIdRequest)
279
280                 APIResponse response = aaiUtil.executeAAIDeleteCall(execution, deleteAAIVolumeGrpIdRequest)
281
282                 String returnCode = response.getStatusCode()
283                 String aaiResponseAsString = response.getResponseBodyAsString()
284
285                 msoLogger.debug("AAI delete volume group return code: " + returnCode)
286                 msoLogger.debug("AAI delete volume group response: " + aaiResponseAsString)
287
288                 ExceptionUtil exceptionUtil = new ExceptionUtil()
289                 if (returnCode=='200' || (returnCode == '204')) {
290                         msoLogger.debug("Volume group $groupId deleted.")
291                 } else {
292                         if (returnCode=='404') {
293                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume group $groupId not found for delete in AAI Response code: 404")
294                         } else {
295                                 WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution)
296                                 throw new BpmnError("MSOWorkflowException")
297                         }
298                 }
299         }
300
301
302         /**
303          * Check if volume group has a relationship to vf-module
304          * @param volumeGroupXml
305          * @return
306          */
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){
317                                                 return true
318                                         }
319                                 }
320                         }
321                 }
322                 return false
323         }
324
325
326         /**
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.
331          */
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()
347                                                         }
348                                                 }
349                                         }
350                                 }
351                         }
352                 }
353                 return null
354         }
355 }