Containerization feature of SO
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / VnfAdapterRestV1.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.apache.commons.lang3.*
24 import org.camunda.bpm.engine.delegate.BpmnError
25 import org.camunda.bpm.engine.delegate.DelegateExecution
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.onap.so.logger.MessageEnum
31 import org.onap.so.logger.MsoLogger
32
33
34
35 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
36         private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, VnfAdapterRestV1.class);
37
38
39         ExceptionUtil exceptionUtil = new ExceptionUtil()
40
41         // VNF Response Processing
42         public void preProcessRequest (DelegateExecution execution) {
43                 def method = getClass().getSimpleName() + '.preProcessRequest(' +
44                         'execution=' + execution.getId() +
45                         ')'
46                 msoLogger.trace('Entered ' + method)
47
48                 def prefix="VNFREST_"
49                 execution.setVariable("prefix", prefix)
50                 setSuccessIndicator(execution, false)
51
52                 try {
53                         String request = validateRequest(execution, "mso-request-id")
54
55                         // Get the request type (the name of the root element) from the request
56
57                         Node root = new XmlParser().parseText(request)
58                         String requestType = root.name()
59                         execution.setVariable(prefix + 'requestType', requestType)
60                         msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType)
61
62                         msoLogger.debug('VnfAdapterRestV1, request: ' + request)
63                         // Get the messageId from the request
64
65                         String messageId = getChildText(root, 'messageId')
66
67                         if ('rollbackVolumeGroupRequest'.equals(requestType)) {
68                                 messageId = getMessageIdForVolumeGroupRollback(root)
69                         }
70                         
71                         if (messageId == null || messageId.isEmpty()) {
72                                 String msg = getProcessKey(execution) + ': no messageId in ' + requestType
73                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
74                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
75                         }
76
77                         execution.setVariable('VNFAResponse_CORRELATOR', messageId)
78                         msoLogger.debug(getProcessKey(execution) + ': VNFAResponse_CORRELATOR = ' + messageId)
79
80                         // Get the notificationUrl from the request
81
82                         String notificationUrl = getChildText(root, 'notificationUrl')
83
84                         if (notificationUrl == null || notificationUrl.isEmpty()) {
85                                 String msg = getProcessKey(execution) + ': no notificationUrl in ' + requestType
86                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
87                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
88                         }
89
90                         execution.setVariable(prefix + 'notificationUrl', notificationUrl)
91                         msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl)
92
93                         // Determine the VnfAdapter endpoint
94
95                         String vnfAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.vnf.rest.endpoint", execution)
96
97                         if (vnfAdapterEndpoint == null || vnfAdapterEndpoint.isEmpty()) {
98                                 String msg = getProcessKey(execution) + ': mso:adapters:vnf:rest:endpoint URN mapping is not defined'
99                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
100                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
101                         }
102
103                         while (vnfAdapterEndpoint.endsWith('/')) {
104                                 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
105                         }
106
107                         String vnfAdapterMethod = null
108                         String vnfAdapterUrl = null
109                         String vnfAdapterRequest = request
110
111                         if ('createVfModuleRequest'.equals(requestType)) {
112                                 String vnfId = getChildText(root, 'vnfId')
113
114                                 if (vnfId == null || vnfId.isEmpty()) {
115                                         String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
116                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
117                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
118                                 }
119
120                                 vnfAdapterMethod = 'POST'
121                                 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
122
123                         } else if ('updateVfModuleRequest'.equals(requestType)) {
124                                 String vnfId = getChildText(root, 'vnfId')
125
126                                 if (vnfId == null || vnfId.isEmpty()) {
127                                         String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
128                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
129                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
130                                 }
131
132                                 String vfModuleId = getChildText(root, 'vfModuleId')
133
134                                 if (vfModuleId == null || vfModuleId.isEmpty()) {
135                                         String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
136                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
137                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
138                                 }
139
140                                 vnfAdapterMethod = 'PUT'
141                                 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
142                                         '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
143
144                         } else if ('deleteVfModuleRequest'.equals(requestType)) {
145                                 String vnfId = getChildText(root, 'vnfId')
146
147                                 if (vnfId == null || vnfId.isEmpty()) {
148                                         String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
149                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
150                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
151                                 }
152
153                                 String vfModuleId = getChildText(root, 'vfModuleId')
154
155                                 if (vfModuleId == null || vfModuleId.isEmpty()) {
156                                         String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
157                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
158                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
159                                 }
160
161                                 vnfAdapterMethod = 'DELETE'
162                                 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
163                                         '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
164
165                         } else if ('rollbackVfModuleRequest'.equals(requestType)) {
166                                 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
167
168                                 if (vfModuleRollbackNode == null) {
169                                         String msg = getProcessKey(execution) + ': no vfModuleRollback in ' + requestType
170                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
171                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
172                                 }
173
174                                 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
175
176                                 if (vnfId == null || vnfId.isEmpty()) {
177                                         String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
178                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
179                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
180                                 }
181
182                                 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
183
184                                 if (vfModuleId == null || vfModuleId.isEmpty()) {
185                                         String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
186                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
187                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
188                                 }
189
190                                 vnfAdapterMethod = 'DELETE'
191                                 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
192                                         '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
193
194                         } else if ('createVolumeGroupRequest'.equals(requestType)) {
195                                 vnfAdapterMethod = 'POST'
196                                 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
197                                         vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
198                                 }
199                                 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
200
201                         } else if ('updateVolumeGroupRequest'.equals(requestType)) {
202                                 String volumeGroupId = getChildText(root, 'volumeGroupId')
203
204                                 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
205                                         String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
206                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
207                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
208                                 }
209
210                                 vnfAdapterMethod = 'PUT'
211                                 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
212                                         vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
213                                 }
214                                 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
215
216                         } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
217                                 String volumeGroupId = getChildText(root, 'volumeGroupId')
218
219                                 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
220                                         String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
221                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
222                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
223                                 }
224
225                                 vnfAdapterMethod = 'DELETE'
226                                 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
227                                         vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
228                                 }
229                                 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
230
231                         } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
232                                 String volumeGroupId = getVolumeGroupIdFromRollbackRequest(root)
233
234                                 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
235                                         String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
236                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
237                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
238                                 }
239
240                                 vnfAdapterMethod = 'DELETE'
241                                 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
242                                         vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
243                                 }
244                                 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')  + '/rollback'
245
246                         } else {
247                                 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
248                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
249                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
250                         }
251
252                         execution.setVariable(prefix + 'vnfAdapterMethod', vnfAdapterMethod)
253                         msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterMethod = ' + vnfAdapterMethod)
254                         execution.setVariable(prefix + 'vnfAdapterUrl', vnfAdapterUrl)
255                         msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterUrl = ' + vnfAdapterUrl)
256                         execution.setVariable(prefix + 'vnfAdapterRequest', vnfAdapterRequest)
257                         msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterRequest = \n' + vnfAdapterRequest)
258
259                         // Get the Basic Auth credentials for the VnfAdapter
260
261                         String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth", execution)
262
263                         if (basicAuthValue == null || basicAuthValue.isEmpty()) {
264                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
265                         } else {
266                                 try {
267                                         def encodedString = utils.getBasicAuth(basicAuthValue, UrnPropertiesReader.getVariable("mso.msoKey", execution))
268                                         execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
269                                 } catch (IOException ex) {
270                                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, getProcessKey(execution) + ": Unable to encode BasicAuth credentials for VnfAdapter", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
271                                 }
272                         }
273
274                 } catch (BpmnError e) {
275                         msoLogger.debug(" Rethrowing MSOWorkflowException")
276                         throw e
277                 } catch (Exception e) {
278                         String msg = 'Caught exception in ' + method + ": " + e
279                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
280                         msoLogger.debug(msg)
281                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
282                 }
283         }
284         
285         public String getVolumeGroupIdFromRollbackRequest(Node root) {
286                 return root.'volumeGroupRollback'.'volumeGroupId'.text()
287         }
288
289         public String getMessageIdForVolumeGroupRollback(Node root) {
290                 return root.'volumeGroupRollback'.'messageId'.text()
291         }
292         
293         /**
294          * This method is used instead of an HTTP Connector task because the
295          * connector does not allow DELETE with a body.
296          */
297         public void sendRequestToVnfAdapter(DelegateExecution execution) {
298                 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
299                         'execution=' + execution.getId() +
300                         ')'
301                 msoLogger.trace('Entered ' + method)
302
303                 String prefix = execution.getVariable('prefix')
304
305                 try {
306                         String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
307                         String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
308                         String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
309
310                         RESTConfig config = new RESTConfig(vnfAdapterUrl)
311                         RESTClient client = new RESTClient(config).
312                                 addHeader("Content-Type", "application/xml").
313                                 addAuthorizationHeader(execution.getVariable(prefix + "basicAuthHeaderValue"));
314
315                         APIResponse response;
316
317                         if ("GET".equals(vnfAdapterMethod)) {
318                                 response = client.httpGet()
319                         } else if ("PUT".equals(vnfAdapterMethod)) {
320                                 response = client.httpPut(vnfAdapterRequest)
321                         } else if ("POST".equals(vnfAdapterMethod)) {
322                                 response = client.httpPost(vnfAdapterRequest)
323                         } else if ("DELETE".equals(vnfAdapterMethod)) {
324                                 response = client.httpDelete(vnfAdapterRequest)
325                         } else {
326                                 String msg = 'Unsupported HTTP method "' + vnfAdapterMethod + '" in ' + method + ": " + e
327                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
328                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
329                         }
330
331                         execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatusCode())
332                         execution.setVariable(prefix + "vnfAdapterResponse", response.getResponseBodyAsString())
333                 } catch (BpmnError e) {
334                         throw e
335                 } catch (Exception e) {
336                         String msg = 'Caught exception in ' + method + ": " + e
337                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
338                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
339                 }
340         }
341
342         public void processCallback(DelegateExecution execution){
343                 def method = getClass().getSimpleName() + '.processCallback(' +
344                         'execution=' + execution.getId() +
345                         ')'
346                 msoLogger.trace('Entered ' + method)
347
348                 String callback = execution.getVariable('VNFAResponse_MESSAGE')
349
350                 try {
351                         msoLogger.debug(getProcessKey(execution) + ": received callback:\n" + callback)
352
353                         // The XML callback is available to the calling flow in any case,
354                         // even if a WorkflowException is generated.
355                         execution.setVariable(getProcessKey(execution) + 'Response', callback)
356                         // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead.
357                         execution.setVariable("WorkflowResponse", callback)
358
359                         Node root = new XmlParser().parseText(callback)
360                         if (root.name().endsWith('Exception')) {
361                                 vnfAdapterWorkflowException(execution, callback)
362                         }
363                 } catch (Exception e) {
364                         e.printStackTrace()
365                         callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
366                         String msg = "Received error from VnfAdapter: " + callback
367                         msoLogger.debug(getProcessKey(execution) + ': ' + msg)
368                         exceptionUtil.buildWorkflowException(execution, 7020, msg)
369                 }
370         }
371
372         /**
373          * Tries to parse the response as XML to extract the information to create
374          * a WorkflowException.  If the response cannot be parsed, a more generic
375          * WorkflowException is created.
376          */
377         public void vnfAdapterWorkflowException(DelegateExecution execution, Object response) {
378                 try {
379                         Node root = new XmlParser().parseText(response)
380                         String category = getChildText(root, "category")
381                         category = category == null || category.isEmpty() ? "" : " category='" + category + "'"
382                         String message = getChildText(root, "message")
383                         message = message == null || message.isEmpty() ? "" : " message='" + message + "'"
384                         String rolledBack = getChildText(root, "rolledBack")
385                         rolledBack = rolledBack == null || rolledBack.isEmpty() ? "" : " rolledBack='" + rolledBack + "'"
386                         exceptionUtil.buildWorkflowException(execution, 7020, "Received " + root.name() +
387                                 " from VnfAdapter:" + category + message + rolledBack);
388                 } catch (Exception e) {
389                         response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
390                         exceptionUtil.buildWorkflowException(execution, 7020, "Received error from VnfAdapter: " + response)
391                 }
392         }
393
394         /**
395          * Gets the named child of the specified node.
396          * @param node the node
397          * @param name the child name
398          * @return the child node, or null if no such child exists
399          */
400         private Node getChild(Node node, String name) {
401                 for (Node child : node.children()) {
402                         if (child.name() == name) {
403                                 return child
404                         }
405                 }
406                 return null
407         }
408
409         /**
410          * Gets the text of the named child of the specified node.
411          * @param node the node
412          * @param name the child name
413          * @return the child node text, or null if no such child exists
414          */
415         private String getChildText(Node node, String name) {
416                 Node child = getChild(node, name)
417                 return child == null ? null : child.text()
418         }
419 }