c455ae90ce30f914a33a96d483b006de72e64c1c
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / UpdateAAIVfModule.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.common.scripts
22
23 import org.camunda.bpm.engine.delegate.BpmnError
24 import org.camunda.bpm.engine.delegate.DelegateExecution
25 import org.onap.so.bpmn.core.WorkflowException
26 import org.onap.so.bpmn.core.UrnPropertiesReader
27 import org.onap.so.client.aai.AAIObjectType
28 import org.onap.so.client.aai.entities.uri.AAIResourceUri
29 import org.onap.so.client.aai.entities.uri.AAIUriFactory
30 import org.onap.so.rest.APIResponse
31 import org.springframework.web.util.UriUtils
32 import org.onap.so.logger.MessageEnum
33 import org.onap.so.logger.MsoLogger
34
35
36
37
38 public class UpdateAAIVfModule extends AbstractServiceTaskProcessor {
39         private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, UpdateAAIVfModule.class);
40
41
42         private XmlParser xmlParser = new XmlParser()
43         ExceptionUtil exceptionUtil = new ExceptionUtil()
44
45         /**
46          * Initialize the flow's variables.
47          *
48          * @param execution The flow's execution instance.
49          */
50         public void initProcessVariables(DelegateExecution execution) {
51                 execution.setVariable('prefix', 'UAAIVfMod_')
52                 execution.setVariable('UAAIVfMod_vnfId', null)
53                 execution.setVariable('UAAIVfMod_vfModuleId', null)
54                 execution.setVariable('UAAIVfMod_orchestrationStatus', null)
55                 execution.setVariable('UAAIVfMod_heatStackId', null)
56                 execution.setVariable('UAAIVfMod_volumeGroupId', null)
57                 execution.setVariable('UAAIVfMod_getVfModuleResponseCode' ,null)
58                 execution.setVariable('UAAIVfMod_getVfModuleResponse', '')
59                 execution.setVariable('UAAIVfMod_updateVfModuleResponseCode', null)
60                 execution.setVariable('UAAIVfMod_updateVfModuleResponse', '')
61         }
62
63         /**
64          * Check for missing elements in the received request.
65          *
66          * @param execution The flow's execution instance.
67          */
68         public void preProcessRequest(DelegateExecution execution) {
69                 def method = getClass().getSimpleName() + '.preProcessRequest(' +
70                         'execution=' + execution.getId() +
71                         ')'
72                 msoLogger.trace('Entered ' + method)
73
74                 try {
75                         def xml = execution.getVariable('UpdateAAIVfModuleRequest')
76                         msoLogger.debug('Received request xml:\n' + xml)
77                         initProcessVariables(execution)
78
79                         def vnfId = getRequiredNodeText(execution, xml,'vnf-id')
80                         execution.setVariable('UAAIVfMod_vnfId', vnfId)
81
82                         def vfModuleId = getRequiredNodeText(execution, xml,'vf-module-id')
83                         execution.setVariable('UAAIVfMod_vfModuleId', vfModuleId)
84
85                         msoLogger.trace('Exited ' + method)
86                 } catch (BpmnError e) {
87                         throw e;
88                 } catch (Exception e) {
89                         msoLogger.error(e);
90                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in preProcessRequest(): ' + e.getMessage())
91                 }
92         }
93
94         /**
95          * Using the received vnfId and vfModuleId, query AAI to get the corresponding VF Module.
96          * A 200 response is expected with the VF Module in the response body.
97          *
98          * @param execution The flow's execution instance.
99          */
100         public void getVfModule(DelegateExecution execution) {
101                 def method = getClass().getSimpleName() + '.getVfModule(' +
102                         'execution=' + execution.getId() +
103                         ')'
104                 msoLogger.trace('Entered ' + method)
105
106                 try {
107                         def vnfId = execution.getVariable('UAAIVfMod_vnfId')
108                         def vfModuleId = execution.getVariable('UAAIVfMod_vfModuleId')
109
110                         AaiUtil aaiUriUtil = new AaiUtil(this)
111                         AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VF_MODULE, vnfId, vfModuleId)
112                         String endPoint = aaiUriUtil.createAaiUri(uri)
113                         
114                         try {
115                                 msoLogger.debug('sending GET to AAI endpoint \'' + endPoint + '\'')
116                                 msoLogger.debug("UpdateAAIVfModule sending GET to AAI endpoint: " + endPoint)
117
118                                 APIResponse response = aaiUriUtil.executeAAIGetCall(execution, endPoint)
119                                 def responseData = response.getResponseBodyAsString()
120                                 execution.setVariable('UAAIVfMod_getVfModuleResponseCode', response.getStatusCode())
121                                 execution.setVariable('UAAIVfMod_getVfModuleResponse', responseData)
122                                 msoLogger.debug('Response code:' + response.getStatusCode())
123                                 msoLogger.debug('Response:' + System.lineSeparator() + responseData)
124                                 msoLogger.debug("UpdateAAIVfModule response data: " + responseData)
125                         } catch (Exception ex) {
126                                 ex.printStackTrace()
127                                 msoLogger.debug('Exception occurred while executing AAI GET:' + ex.getMessage())
128                                 execution.setVariable('UAAIVfMod_getVfModuleResponseCode', 500)
129                                 execution.setVariable('UAAIVfMod_getVfModuleResponse', 'AAI GET Failed:' + ex.getMessage())
130                         }
131                         msoLogger.trace('Exited ' + method)
132                 } catch (BpmnError e) {
133                         throw e;
134                 } catch (Exception e) {
135                         msoLogger.error(e);
136                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in getVfModule(): ' + e.getMessage())
137                 }
138         }
139
140         /**
141          * Construct and send a PATCH request to AAI to update the VF Module.
142          *
143          * @param execution The flow's execution instance.
144          */
145         public void updateVfModule(DelegateExecution execution) {
146                 def method = getClass().getSimpleName() + '.updateVfModule(' +
147                         'execution=' + execution.getId() +
148                         ')'
149                 msoLogger.trace('Entered ' + method)
150
151                 try {
152                         def vnfId = execution.getVariable('UAAIVfMod_vnfId')
153                         def vfModuleId = execution.getVariable('UAAIVfMod_vfModuleId')
154                         def vfModule = execution.getVariable('UAAIVfMod_getVfModuleResponse')
155                         def origRequest = execution.getVariable('UpdateAAIVfModuleRequest')
156                         def Node vfModuleNode = xmlParser.parseText(vfModule)
157                         
158                         msoLogger.debug("UpdateAAIVfModule request: " + origRequest)
159                         // Confirm resource-version is in retrieved VF Module
160                         if (utils.getChildNode(vfModuleNode, 'resource-version') == null) {
161                                 def msg = 'Can\'t update VF Module ' + vfModuleId + ' since \'resource-version\' is missing'
162                                 msoLogger.error(msg);
163                                 throw new Exception(msg)
164                         }
165                         
166                         // Handle persona-model-id/persona-model-version
167                         def boolean doPersonaModelVersion = true
168                         def String newPersonaModelId = utils.getNodeText(origRequest, 'persona-model-id')
169                         def String newPersonaModelVersion = utils.getNodeText(origRequest, 'persona-model-version')
170                         if ((newPersonaModelId == null) || (newPersonaModelVersion == null)) {
171                                 doPersonaModelVersion = false
172                         } else {
173                                 // Confirm "new" persona-model-id is same as "current" persona-model-id
174                                 def String currPersonaModelId = utils.getChildNodeText(vfModuleNode, 'model-invariant-id')
175                                 if (currPersonaModelId == null) {
176                                         // check the old attribute name
177                                         currPersonaModelId = utils.getChildNodeText(vfModuleNode, 'model-version-id')
178                                 }
179                                 if (currPersonaModelId == null) {
180                                         currPersonaModelId = ''
181                                 }
182                                 if (!newPersonaModelId.equals(currPersonaModelId)) {
183                                         def msg = 'Can\'t update VF Module ' + vfModuleId + ' since there is \'persona-model-id\' mismatch between the current and new values'
184                                         msoLogger.error(msg)
185                                         throw new Exception(msg)
186                                 }
187                         }
188                         
189                         // Construct payload
190                         String orchestrationStatusEntry = updateVfModuleNode(origRequest, vfModuleNode, 'orchestration-status')
191                         String heatStackIdEntry = updateVfModuleNode(origRequest, vfModuleNode, 'heat-stack-id')
192                         String personaModelVersionEntry = ""
193                         if (doPersonaModelVersion) {
194                                 personaModelVersionEntry = updateVfModuleNode(origRequest, vfModuleNode, 'persona-model-version')
195                         }
196                         String contrailServiceInstanceFqdnEntry = updateVfModuleNode(origRequest, vfModuleNode, 'contrail-service-instance-fqdn')
197                         def payload = """
198                                         {       ${orchestrationStatusEntry}
199                                                 ${heatStackIdEntry}
200                                                 ${personaModelVersionEntry}
201                                                 ${contrailServiceInstanceFqdnEntry}
202                                                 "vf-module-id": "${vfModuleId}"                                         
203                                         }
204                         """
205
206                         AaiUtil aaiUriUtil = new AaiUtil(this)
207                         AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VF_MODULE, vnfId, vfModuleId)
208                         String endPoint = aaiUriUtil.createAaiUri(uri)
209
210                         try {
211                                 msoLogger.debug('sending PATCH to AAI endpoint \'' + endPoint + '\'' + 'with payload \n' + payload)
212                                 msoLogger.debug("Sending PATCH to AAI endpoint: " + endPoint)
213
214                                 APIResponse response = aaiUriUtil.executeAAIPatchCall(execution, endPoint, payload)
215                                 def responseData = response.getResponseBodyAsString()
216                                 execution.setVariable('UAAIVfMod_updateVfModuleResponseCode', response.getStatusCode())
217                                 execution.setVariable('UAAIVfMod_updateVfModuleResponse', responseData)
218                                 msoLogger.debug("UpdateAAIVfModule Response data: " + responseData)
219                                 msoLogger.debug('Response code:' + response.getStatusCode())
220                                 msoLogger.debug('Response:' + System.lineSeparator() + responseData)
221                         } catch (Exception ex) {
222                                 ex.printStackTrace()
223                                 msoLogger.debug('Exception occurred while executing AAI PATCH:' + ex.getMessage())
224                                 execution.setVariable('UAAIVfMod_updateVfModuleResponseCode', 500)
225                                 execution.setVariable('UAAIVfMod_updateVfModuleResponse', 'AAI PATCH Failed:' + ex.getMessage())
226                         }
227                         msoLogger.trace('Exited ' + method)
228                 } catch (BpmnError e) {
229                         throw e;
230                 } catch (Exception e) {
231                         msoLogger.error(e);
232                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in updateVfModule(): ' + e.getMessage())
233                 }
234         }
235
236         /**
237          * Sets up json attributes for PATCH request for Update
238          *
239          * @param origRequest Incoming update request with VF Module elements to be updated.
240          * @param vfModule Current VF Module retrieved from AAI.
241          * @param element Name of element to be inserted.
242          */     
243         private String updateVfModuleNode(String origRequest, Node vfModuleNode, String elementName) {
244
245                 if (!utils.nodeExists(origRequest, elementName)) {
246                         return "" 
247                 }
248                 def elementValue = utils.getNodeText(origRequest, elementName)
249
250                 if (elementValue.equals('DELETE')) {
251                         // Set the element being deleted to null
252                         return """"${elementName}": null,"""
253                 }
254                 else {
255                         return """"${elementName}": "${elementValue}","""
256                 }               
257         }
258
259         
260         /**
261          * Check the Volume Group ID from the incoming update request against the Volume Group ID from the
262          * given VF Module.  If they are equal or if they are both 'null', then that is acceptable and 'null'
263          * is returned.  Otherwise a message describing how the values are unacceptable/incompatible is returned.
264          * 
265          * @param origRequest Incoming update request with VF Module elements to be updated.
266          * @param vfModuleNode VF Module (as a Node) retrieved from AAI.
267          * @param isDebugLogEnabled Is DEBUG log enabled?
268          * @return 'null' if the Volume Group IDs are acceptable. Otherwise return a message describing how the
269          * values are unacceptable/incompatible.
270          */
271         private String checkVolumeGroupId(String origRequest, Node vfModuleNode, String isDebugLogEnabled) {
272                 def requestVolumeGroupId = utils.getNodeText(origRequest, 'volume-group-id')
273                 def currVolumeGroupId = getCurrVolumeGroupId(vfModuleNode)
274                 
275                 msoLogger.debug('Check volume-group-id: volume-group-id in original request is \'' + requestVolumeGroupId + '\', volume-group-id from VF Module is \'' + currVolumeGroupId + '\'')
276                 
277                 def result = null
278                 
279                 if (requestVolumeGroupId == null) {
280                         if (currVolumeGroupId == null) {
281                                 // This is OK
282                         } else {
283                                 result = 'Cannot detach a volume group from an existing VF Module'
284                         }
285                 } else {
286                         if (currVolumeGroupId == null) {
287                                 result = 'Cannot add a volume gruop to an existing VF Module'
288                         } else {
289                                 if (!requestVolumeGroupId.equals(currVolumeGroupId)) {
290                                         result = 'Cannot change the volume group on an existing VF Module'
291                                 }
292                         }
293                 }
294                 
295                 return result
296         }
297         
298         /**
299          * Find and return the value of the Volume Group ID for the specified VF Module.  If
300          * the value of the Volume Group ID cannot be found for any reason, 'null' is returned.
301          * 
302          * @param vfModuleNode VF Module (as a Node) retrieved from AAI.
303          * @return the value of the Volume Group ID for the specified VF Module.  If the
304          * value of the Volume Group ID cannot be found for any reason, 'null' is returned.
305          */
306         private String getCurrVolumeGroupId(Node vfModuleNode) {
307                 def Node relationshipList = utils.getChildNode(vfModuleNode, 'relationship-list')
308                 if (relationshipList == null) {
309                         return null
310                 }
311                 def NodeList relationships = utils.getIdenticalChildren(relationshipList, 'relationship')
312                 for (Node relationshipNode in relationships) {
313                         def String relatedTo = utils.getChildNodeText(relationshipNode, 'related-to')
314                         if ((relatedTo != null) && relatedTo.equals('volume-group')) {
315                                 def NodeList relationshipDataList = utils.getIdenticalChildren(relationshipNode, 'relationship-data')
316                                 for (Node relationshipDataNode in relationshipDataList) {
317                                         def String relationshipKey = utils.getChildNodeText(relationshipDataNode, 'relationship-key')
318                                         if ((relationshipKey != null) && relationshipKey.equals('volume-group.volume-group-id')) {
319                                                 return utils.getChildNodeText(relationshipDataNode, 'relationship-value')
320                                         }
321                                 }
322                         }
323                 }
324                 return null
325         }
326
327         /**
328          * Generates a WorkflowException if the AAI query returns a response code other than 200.
329          *
330          * @param execution The flow's execution instance.
331          */
332         public void handleAAIQueryFailure(DelegateExecution execution) {
333                 def method = getClass().getSimpleName() + '.handleAAIQueryFailure(' +
334                         'execution=' + execution.getId() +
335                         ')'
336                 msoLogger.trace('Entered ' + method)
337
338                 msoLogger.error( 'Error occurred attempting to query AAI, Response Code ' + execution.getVariable('UAAIVfMod_getVfModuleResponseCode'));
339                 String processKey = getProcessKey(execution);
340                 WorkflowException exception = new WorkflowException(processKey, 5000,
341                         execution.getVariable('UAAIVfMod_getVfModuleResponse'))
342                 execution.setVariable('WorkflowException', exception)
343                 msoLogger.debug("UpdateAAIVfModule query failure: " + exception.getErrorMessage())
344                 msoLogger.trace('Exited ' + method)
345         }
346
347         /**
348          * Generates a WorkflowException if updating a VF Module in AAI returns a response code other than 200.
349          *
350          * @param execution The flow's execution instance.
351          */
352         public void handleUpdateVfModuleFailure(DelegateExecution execution) {
353                 def method = getClass().getSimpleName() + '.handleUpdateVfModuleFailure(' +
354                         'execution=' + execution.getId() +
355                         ')'
356                 msoLogger.trace('Entered ' + method)
357
358                 msoLogger.error('Error occurred attempting to update VF Module in AAI, Response Code ' + execution.getVariable('UAAIVfMod_updateVfModuleResponseCode'));
359                 String processKey = getProcessKey(execution);
360                 WorkflowException exception = new WorkflowException(processKey, 5000,
361                         execution.getVariable('UAAIVfMod_updateVfModuleResponse'))
362                 execution.setVariable('WorkflowException', exception)
363
364                 msoLogger.debug("UpdateAAIVfModule failure: " + exception.getErrorMessage())
365                 msoLogger.trace('Exited ' + method)
366         }
367 }