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