Containerization feature of SO
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / PrepareUpdateAAIVfModule.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.rest.APIResponse
28 import org.onap.so.rest.RESTClient
29 import org.onap.so.rest.RESTConfig
30 import org.springframework.web.util.UriUtils
31 import org.onap.so.logger.MessageEnum
32 import org.onap.so.logger.MsoLogger
33
34
35
36 public class PrepareUpdateAAIVfModule extends VfModuleBase {
37         private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, PrepareUpdateAAIVfModule.class);
38
39         
40         ExceptionUtil exceptionUtil = new ExceptionUtil()
41         private MsoUtils utils = new MsoUtils()
42         /**
43          * Initialize the flow's variables.
44          * 
45          * @param execution The flow's execution instance.
46          */
47         public void initProcessVariables(DelegateExecution execution) {
48                 execution.setVariable('prefix', 'PUAAIVfMod_')
49                 execution.setVariable('PUAAIVfMod_vnfId', null)
50                 execution.setVariable('PUAAIVfMod_vfModuleId', null)
51                 execution.setVariable('PUAAIVfMod_vnfName', null)
52                 execution.setVariable('PUAAIVfMod_orchestrationStatus', null)
53                 execution.setVariable('PUAAIVfMod_vfModule', null)
54                 execution.setVariable('PUAAIVfMod_vfModuleOK', false)
55                 execution.setVariable('PUAAIVfMod_vfModuleValidationError', null)
56                 execution.setVariable('PUAAIVfMod_getVnfResponseCode' ,null)
57                 execution.setVariable('PUAAIVfMod_getVnfResponse', '')
58                 execution.setVariable('PUAAIVfMod_updateVfModuleResponseCode', null)
59                 execution.setVariable('PUAAIVfMod_updateVfModuleResponse', '')
60                 execution.setVariable('PUAAIVfMod_outVfModule', null)
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('PrepareUpdateAAIVfModuleRequest')
76                         msoLogger.debug('Received request xml:\n' + xml)
77                         msoLogger.debug("PrepareUpdateAAIVfModule Request  : " + xml)
78                         
79                         initProcessVariables(execution)
80                         
81                         def vnfId = getRequiredNodeText(execution, xml,'vnf-id')
82                         execution.setVariable('PUAAIVfMod_vnfId', vnfId)
83
84                         def vfModuleId = getRequiredNodeText(execution, xml,'vf-module-id')
85                         execution.setVariable('PUAAIVfMod_vfModuleId', vfModuleId)
86                         
87                         def orchestrationStatus = getRequiredNodeText(execution, xml,'orchestration-status')
88                         execution.setVariable('PUAAIVfMod_orchestrationStatus', orchestrationStatus)
89
90                         msoLogger.trace('Exited ' + method)
91                 } catch (BpmnError e) {
92                         throw e;
93                 } catch (Exception e) {
94                         msoLogger.error(e)
95                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in preProcessRequest(): ' + e.getMessage())
96                 }
97         }
98         
99         /**
100          * Using the received vnfId, query AAI to get the corresponding Generic VNF.
101          * A 200 response is expected with the Generic VNF in the response body.
102          * 
103          * @param execution The flow's execution instance.
104          */
105         public void getGenericVnf(DelegateExecution execution) {
106                 def method = getClass().getSimpleName() + '.getGenericVnf(' +
107                         'execution=' + execution.getId() +
108                         ')'
109                 msoLogger.trace('Entered ' + method)
110
111                 try {
112                         def vnfId = execution.getVariable('PUAAIVfMod_vnfId')
113                         
114                         AaiUtil aaiUriUtil = new AaiUtil(this)
115                         def aai_uri = aaiUriUtil.getNetworkGenericVnfUri(execution)
116                         msoLogger.debug('AAI URI is: ' + aai_uri)
117                         
118                         String endPoint = UrnPropertiesReader.getVariable("aai.endpoint", execution) + "${aai_uri}/" + UriUtils.encode(vnfId, "UTF-8") + "?depth=1"
119                                 
120                         msoLogger.debug("PrepareUpdateAAIVfModule: AAI endPoint  : " + endPoint)
121                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
122                         try {
123                                 RESTConfig config = new RESTConfig(endPoint);
124                                 def responseData = ''
125                                 String aaiRequestId = utils.getRequestID()
126                                 RESTClient client = new RESTClient(config).
127                                         addHeader('X-TransactionId', aaiRequestId).
128                                         addHeader('X-FromAppId', 'MSO').
129                                         addHeader('Content-Type', 'application/xml').
130                                         addHeader('Accept','application/xml');
131                                 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
132                                         client.addAuthorizationHeader(basicAuthCred)
133                                 }
134                                 msoLogger.debug('sending GET to AAI endpoint \'' + endPoint + '\'')
135                                 APIResponse response = client.httpGet()
136                                 msoLogger.debug("PrepareUpdateAAIVfModule: - invoking httpGet to AAI")
137                                 
138                                 responseData = response.getResponseBodyAsString()
139                                 execution.setVariable('PUAAIVfMod_getVnfResponseCode', response.getStatusCode())
140                                 execution.setVariable('PUAAIVfMod_getVnfResponse', responseData)
141                                 
142                                 msoLogger.debug("PrepareUpdateAAIVfModule: AAI Response : " + responseData)
143                                 msoLogger.debug("PrepareUpdateAAIVfModule: AAI ResponseCode : " + response.getStatusCode())
144                                 
145                                 msoLogger.debug('Response code:' + response.getStatusCode())
146                                 msoLogger.debug('Response:' + System.lineSeparator() + responseData)
147                         } catch (Exception ex) {
148                                 msoLogger.error(ex);
149                                 msoLogger.debug('Exception occurred while executing AAI GET:' + ex.getMessage())
150                                 execution.setVariable('PUAAIVfMod_getVnfResponseCode', 500)
151                                 execution.setVariable('PUAAIVfMod_getVnfResponse', 'AAI GET Failed:' + ex.getMessage())
152                         }
153                         msoLogger.trace('Exited ' + method)
154                 } catch (BpmnError e) {
155                         throw e;
156                 } catch (Exception e) {
157                         msoLogger.error(e)
158                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in getGenericVnf(): ' + e.getMessage())
159                 }
160         }
161         
162         /**
163          * Validate the VF Module.  That is, confirm that a VF Module with the input VF Module ID
164          * exists in the retrieved Generic VNF.  Then, check to make sure that if that VF Module
165          * is the base VF Module and it's not the only VF Module for this Generic VNF, that we're not
166          * attempting to delete it.
167          * 
168          * @param execution The flow's execution instance.
169          */
170         public void validateVfModule(DelegateExecution execution) {
171                 def method = getClass().getSimpleName() + '.validateVfModule(' +
172                         'execution=' + execution.getId() +
173                         ')'
174                 msoLogger.trace('Entered ' + method)
175                 
176                 try {
177                         def genericVnf = execution.getVariable('PUAAIVfMod_getVnfResponse')
178                         def vnfId = execution.getVariable('PUAAIVfMod_vnfId')
179                         def vfModuleId = execution.getVariable('PUAAIVfMod_vfModuleId')
180                         def vnfName = getNodeTextForce(genericVnf, 'vnf-name')
181                         execution.setVariable('PUAAIVfMod_vnfName', vnfName)
182                         def VfModule vfModule = findVfModule(genericVnf, vfModuleId)
183                         if (vfModule == null) {
184                                 def String msg = 'VF Module \'' + vfModuleId + '\' does not exist in Generic VNF \'' + vnfId + '\''
185                                 execution.setVariable('PUAAIVfMod_vfModuleValidationError', msg)
186                                 execution.setVariable('PUAAIVfMod_vfModuleOK', false)
187                         } else {
188                                 def orchestrationStatus = execution.getVariable('PUAAIVfMod_orchestrationStatus')
189                                 msoLogger.debug('VF Module \'' + vfModuleId + '\': isBaseVfModule=' + vfModule.isBaseVfModule() +', isOnlyVfModule=' + vfModule.isOnlyVfModule() + ', new orchestration-status=' + orchestrationStatus)
190                                 if (vfModule.isBaseVfModule() && !vfModule.isOnlyVfModule() && orchestrationStatus.equals('pending-delete')) {
191                                         def String msg = 'Orchestration status for VF Module \'' + vfModuleId +
192                                                 '\' cannot be set to \'pending-delete\' since it is the base VF Module and it\'s not the only VF Module in Generic VNF \'' + vnfId + '\''
193                                         execution.setVariable('PUAAIVfMod_vfModuleValidationError', msg)
194                                         execution.setVariable('PUAAIVfMod_vfModuleOK', false)
195                                 } else {
196                                         execution.setVariable('PUAAIVfMod_vfModule', vfModule)
197                                         execution.setVariable('PUAAIVfMod_vfModuleOK', true)
198                                 }
199                         }
200                         
201                         msoLogger.trace('Exited ' + method)
202                 } catch (BpmnError e) {
203                         throw e;
204                 } catch (Exception e) {
205                         msoLogger.error(e)
206                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in validateVfModule(): ' + e.getMessage())
207                 }
208         }
209         
210         /**
211          * Construct and send a PATCH request to AAI to update the VF Module.
212          * 
213          * @param execution The flow's execution instance.
214          */
215         public void updateVfModule(DelegateExecution execution) {
216                 def method = getClass().getSimpleName() + '.updateVfModule(' +
217                         'execution=' + execution.getId() +
218                         ')'
219                 msoLogger.trace('Entered ' + method)
220                 
221                 try {
222                         // Construct payload
223                         def VfModule vfModule = (VfModule) execution.getVariable('PUAAIVfMod_vfModule')
224                         def Node newVfModuleNode = vfModule.getNode().clone()
225                         def orchestrationStatus = execution.getVariable('PUAAIVfMod_orchestrationStatus')
226                         def Node orchestrationStatusNode = utils.getChildNode(newVfModuleNode, 'orchestration-status')
227                         if (orchestrationStatusNode == null) {
228                                 // Node doesn't exist, this should never happen, right?
229                                 new Node(newVfModuleNode, 'orchestration-status', orchestrationStatus)
230                         } else {
231                                 // Node already exists, just give it a new value
232                                 orchestrationStatusNode.setValue(orchestrationStatus)
233                         }
234                         def VfModule newVfModule = new VfModule(newVfModuleNode, vfModule.isOnlyVfModule())
235                         //def payload = utils.nodeToString(newVfModuleNode)
236                                         
237                         // Construct endpoint
238                         def vnfId = execution.getVariable('PUAAIVfMod_vnfId')
239                         def vfModuleId = execution.getVariable('PUAAIVfMod_vfModuleId')
240                         
241                         def payload = """{
242                                         "vf-module-id": "${vfModuleId}",
243                                         "orchestration-status": "${orchestrationStatus}"
244                                 }"""
245                         
246                         msoLogger.debug("VfModule payload : " + payload)
247
248                         AaiUtil aaiUriUtil = new AaiUtil(this)
249                         def aai_uri = aaiUriUtil.getNetworkGenericVnfUri(execution)
250                         msoLogger.debug('AAI URI is: ' + aai_uri)
251                         
252                         String endPoint = UrnPropertiesReader.getVariable("aai.endpoint", execution) + "${aai_uri}/" + UriUtils.encode(vnfId, "UTF-8") + "/vf-modules/vf-module/" + UriUtils.encode(vfModuleId, "UTF-8")
253                         msoLogger.debug("PrepareUpdateAAIVfModule: AAI endPoint  : " + endPoint)
254                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
255                         try {
256                                 RESTConfig config = new RESTConfig(endPoint);
257                                 def responseData = ''
258                 def aaiRequestId = utils.getRequestID()
259                                 RESTClient client = new RESTClient(config).
260                                         addHeader('X-TransactionId', aaiRequestId).
261                                         addHeader('X-FromAppId', 'MSO').
262                                         addHeader('Content-Type', 'application/merge-patch+json').
263                                         addHeader('Accept','application/json');
264                                 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
265                                         client.addAuthorizationHeader(basicAuthCred)
266                                 }
267                                 msoLogger.debug('sending PATCH to AAI endpoint \'' + endPoint + '\'' + 'with payload \n' + payload)
268                                 APIResponse response = client.httpPatch(payload)
269                                 msoLogger.debug("PrepareUpdateAAIVfModule: - invoking httpPatch to AAI")
270
271                                 responseData = response.getResponseBodyAsString()
272                                 execution.setVariable('PUAAIVfMod_updateVfModuleResponseCode', response.getStatusCode())
273                                 execution.setVariable('PUAAIVfMod_updateVfModuleResponse', responseData)
274                                 msoLogger.debug('Response code:' + response.getStatusCode())
275                                 msoLogger.debug('Response:' + System.lineSeparator() + responseData)
276                                 msoLogger.debug("PrepareUpdateAAIVfModule: AAI Response : " + responseData)
277                                 msoLogger.debug("PrepareUpdateAAIVfModule: AAI ResponseCode : " + response.getStatusCode())
278                                 
279                                 // Set the output for this flow.  The updated VfModule is an output, the generic VNF name, and for
280                                 // backward compatibilty, the heat-stack-id is an output
281                                 execution.setVariable('PUAAIVfMod_outVfModule', newVfModule)
282                                 def vnfName = execution.getVariable('PUAAIVfMod_vnfName')
283                                 msoLogger.debug('Output PUAAIVfMod_vnfName set to ' + vnfName)
284                                 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead
285                                 execution.setVariable('WorkflowResponse', newVfModule)
286                                 msoLogger.debug('Output PUAAIVfMod_outVfModule set for VF Module Id \'' + newVfModule.getElementText('vf-module-id') + '\'')
287                                 def heatStackId = newVfModule.getElementText('heat-stack-id')
288                                 execution.setVariable('PUAAIVfMod_heatStackId', heatStackId)
289                                 msoLogger.debug('Output PUAAIVfMod_heatStackId set to \'' + heatStackId + '\'')
290                         } catch (Exception ex) {
291                                 ex.printStackTrace()
292                                 msoLogger.debug('Exception occurred while executing AAI PUT:' + ex.getMessage())
293                                 execution.setVariable('PUAAIVfMod_updateVfModuleResponseCode', 500)
294                                 execution.setVariable('PUAAIVfMod_updateVfModuleResponse', 'AAI PATCH Failed:' + ex.getMessage())
295                         }
296                         msoLogger.trace('Exited ' + method)
297                 } catch (BpmnError e) {
298                         throw e;
299                 } catch (Exception e) {
300                         msoLogger.error(e)
301                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in updateVfModule(): ' + e.getMessage())
302                 }                               
303         }
304                 
305         /**
306          * Generates a WorkflowException if the AAI query returns a response code other than 200.
307          * 
308          * @param execution The flow's execution instance.
309          */
310         public void handleVnfNotFound(DelegateExecution execution) {
311                 def method = getClass().getSimpleName() + '.handleVnfNotFound(' +
312                         'execution=' + execution.getId() +
313                         ')'
314                 msoLogger.trace('Entered ' + method)
315
316                 msoLogger.error('Error occurred attempting to query AAI, Response Code ' + execution.getVariable('PUAAIVfMod_getVnfResponseCode'));
317                 String processKey = getProcessKey(execution);
318                 WorkflowException exception = new WorkflowException(processKey, 5000,
319                         execution.getVariable('PUAAIVfMod_getVnfResponse'))
320                 execution.setVariable('WorkflowException', exception)
321                 
322                 msoLogger.trace('Exited ' + method)
323         }
324         
325         /**
326          * Generates a WorkflowException if the VF Module does not pass validation.
327          * 
328          * @param execution The flow's execution instance.
329          */
330         public void handleVfModuleValidationError(DelegateExecution execution) {
331                 def method = getClass().getSimpleName() + '.handleVfModuleValidationError(' +
332                         'execution=' + execution.getId() +
333                         ')'
334                 msoLogger.trace('Entered ' + method)
335                                 
336                 def String errorMsg = 'VF Module validation error: ' + execution.getVariable('PUAAIVfMod_vfModuleValidationError')
337                 msoLogger.error(errorMsg);
338                 msoLogger.debug("PrepareUpdateAAIVfModule: Error Message : " + errorMsg)
339                 
340                 String processKey = getProcessKey(execution);
341                 WorkflowException exception = new WorkflowException(processKey, 5000, errorMsg)
342                 execution.setVariable('WorkflowException', exception)
343
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('PUAAIVfMod_updateVfModuleResponseCode'));
359                 String processKey = getProcessKey(execution);
360                 WorkflowException exception = new WorkflowException(processKey, 5000,
361                         execution.getVariable('PUAAIVfMod_updateVfModuleResponse'))
362                 execution.setVariable('WorkflowException', exception)
363                 
364                 msoLogger.trace('Exited ' + method)
365         }
366 }