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