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