remove multiline strings with A&AI client
[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                         org.onap.aai.domain.yang.VfModule payload = new org.onap.aai.domain.yang.VfModule();
178                         payload.setVfModuleId(vfModuleId)
179                         payload.setOrchestrationStatus(orchestrationStatusEntry)
180                         payload.setHeatStackId(heatStackIdEntry)
181                         payload.setPersonaModelVersion(personaModelVersionEntry)
182                         payload.setContrailServiceInstanceFqdn(contrailServiceInstanceFqdnEntry)
183
184             try {
185                 AAIResourceUri resourceUri = AAIUriFactory.createResourceUri(AAIObjectType.VF_MODULE, vnfId, vfModuleId)
186                 getAAIClient().update(resourceUri, payload)
187             }catch(NotFoundException ignored){
188                 msoLogger.debug("VF-Module not found!!")
189                 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "vf-module " + vfModuleId + " not found for under vnf " + vnfId + " in A&AI!")
190             }
191             catch(Exception ex){
192                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, 'Exception occurred while executing AAI PATCH:' + ex.getMessage())
193             }
194                 } catch (BpmnError e) {
195                         throw e;
196                 } catch (Exception e) {
197                         msoLogger.error(e);
198                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in updateVfModule(): ' + e.getMessage())
199                 }
200         }
201
202         /**
203          * Sets up json attributes for PATCH request for Update
204          *
205          * @param origRequest Incoming update request with VF Module elements to be updated.
206          * @param element Name of element to be inserted.
207          */     
208         private String updateVfModuleNode(String origRequest, String elementName) {
209
210                 if (!utils.nodeExists(origRequest, elementName)) {
211                         return null
212                 }
213                 def elementValue = utils.getNodeText(origRequest, elementName)
214
215                 if (elementValue.equals('DELETE')) {
216                         // Set the element being deleted to empty string
217                         return ""
218                 }
219                 else {
220                         return elementValue
221                 }               
222         }
223
224         
225         /**
226          * Check the Volume Group ID from the incoming update request against the Volume Group ID from the
227          * given VF Module.  If they are equal or if they are both 'null', then that is acceptable and 'null'
228          * is returned.  Otherwise a message describing how the values are unacceptable/incompatible is returned.
229          * 
230          * @param origRequest Incoming update request with VF Module elements to be updated.
231          * @param vfModuleNode VF Module (as a Node) retrieved from AAI.
232          * @param isDebugLogEnabled Is DEBUG log enabled?
233          * @return 'null' if the Volume Group IDs are acceptable. Otherwise return a message describing how the
234          * values are unacceptable/incompatible.
235          */
236         private String checkVolumeGroupId(String origRequest, Node vfModuleNode, String isDebugLogEnabled) {
237                 def requestVolumeGroupId = utils.getNodeText(origRequest, 'volume-group-id')
238                 def currVolumeGroupId = getCurrVolumeGroupId(vfModuleNode)
239                 
240                 msoLogger.debug('Check volume-group-id: volume-group-id in original request is \'' + requestVolumeGroupId + '\', volume-group-id from VF Module is \'' + currVolumeGroupId + '\'')
241                 
242                 def result = null
243                 
244                 if (requestVolumeGroupId == null) {
245                         if (currVolumeGroupId == null) {
246                                 // This is OK
247                         } else {
248                                 result = 'Cannot detach a volume group from an existing VF Module'
249                         }
250                 } else {
251                         if (currVolumeGroupId == null) {
252                                 result = 'Cannot add a volume gruop to an existing VF Module'
253                         } else {
254                                 if (!requestVolumeGroupId.equals(currVolumeGroupId)) {
255                                         result = 'Cannot change the volume group on an existing VF Module'
256                                 }
257                         }
258                 }
259                 
260                 return result
261         }
262         
263         /**
264          * Find and return the value of the Volume Group ID for the specified VF Module.  If
265          * the value of the Volume Group ID cannot be found for any reason, 'null' is returned.
266          * 
267          * @param vfModuleNode VF Module (as a Node) retrieved from AAI.
268          * @return the value of the Volume Group ID for the specified VF Module.  If the
269          * value of the Volume Group ID cannot be found for any reason, 'null' is returned.
270          */
271         private String getCurrVolumeGroupId(Node vfModuleNode) {
272                 def Node relationshipList = utils.getChildNode(vfModuleNode, 'relationship-list')
273                 if (relationshipList == null) {
274                         return null
275                 }
276                 def NodeList relationships = utils.getIdenticalChildren(relationshipList, 'relationship')
277                 for (Node relationshipNode in relationships) {
278                         def String relatedTo = utils.getChildNodeText(relationshipNode, 'related-to')
279                         if ((relatedTo != null) && relatedTo.equals('volume-group')) {
280                                 def NodeList relationshipDataList = utils.getIdenticalChildren(relationshipNode, 'relationship-data')
281                                 for (Node relationshipDataNode in relationshipDataList) {
282                                         def String relationshipKey = utils.getChildNodeText(relationshipDataNode, 'relationship-key')
283                                         if ((relationshipKey != null) && relationshipKey.equals('volume-group.volume-group-id')) {
284                                                 return utils.getChildNodeText(relationshipDataNode, 'relationship-value')
285                                         }
286                                 }
287                         }
288                 }
289                 return null
290         }
291
292         /**
293          * Generates a WorkflowException if the AAI query returns a response code other than 200.
294          *
295          * @param execution The flow's execution instance.
296          */
297         public void handleAAIQueryFailure(DelegateExecution execution) {
298                 def method = getClass().getSimpleName() + '.handleAAIQueryFailure(' +
299                         'execution=' + execution.getId() +
300                         ')'
301                 msoLogger.trace('Entered ' + method)
302
303                 msoLogger.error( 'Error occurred attempting to query AAI, Response Code ' + execution.getVariable('UAAIVfMod_getVfModuleResponseCode'));
304                 String processKey = getProcessKey(execution);
305                 WorkflowException exception = new WorkflowException(processKey, 5000,
306                         execution.getVariable('UAAIVfMod_getVfModuleResponse'))
307                 execution.setVariable('WorkflowException', exception)
308                 msoLogger.debug("UpdateAAIVfModule query failure: " + exception.getErrorMessage())
309                 msoLogger.trace('Exited ' + method)
310         }
311 }