2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.so.bpmn.common.scripts
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
35 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
36 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, VnfAdapterRestV1.class);
39 ExceptionUtil exceptionUtil = new ExceptionUtil()
41 // VNF Response Processing
42 public void preProcessRequest (DelegateExecution execution) {
43 def method = getClass().getSimpleName() + '.preProcessRequest(' +
44 'execution=' + execution.getId() +
46 msoLogger.trace('Entered ' + method)
49 execution.setVariable("prefix", prefix)
50 setSuccessIndicator(execution, false)
53 String request = validateRequest(execution, "mso-request-id")
55 // Get the request type (the name of the root element) from the request
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)
62 msoLogger.debug('VnfAdapterRestV1, request: ' + request)
63 // Get the messageId from the request
65 String messageId = getChildText(root, 'messageId')
67 if ('rollbackVolumeGroupRequest'.equals(requestType)) {
68 messageId = getMessageIdForVolumeGroupRollback(root)
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)
77 execution.setVariable('VNFAResponse_CORRELATOR', messageId)
78 msoLogger.debug(getProcessKey(execution) + ': VNFAResponse_CORRELATOR = ' + messageId)
80 // Get the notificationUrl from the request
82 String notificationUrl = getChildText(root, 'notificationUrl')
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)
90 execution.setVariable(prefix + 'notificationUrl', notificationUrl)
91 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl)
93 // Determine the VnfAdapter endpoint
95 String vnfAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.vnf.rest.endpoint", execution)
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)
103 while (vnfAdapterEndpoint.endsWith('/')) {
104 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
107 String vnfAdapterMethod = null
108 String vnfAdapterUrl = null
109 String vnfAdapterRequest = request
111 if ('createVfModuleRequest'.equals(requestType)) {
112 String vnfId = getChildText(root, 'vnfId')
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)
120 vnfAdapterMethod = 'POST'
121 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
123 } else if ('updateVfModuleRequest'.equals(requestType)) {
124 String vnfId = getChildText(root, 'vnfId')
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)
132 String vfModuleId = getChildText(root, 'vfModuleId')
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)
140 vnfAdapterMethod = 'PUT'
141 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
142 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
144 } else if ('deleteVfModuleRequest'.equals(requestType)) {
145 String vnfId = getChildText(root, 'vnfId')
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)
153 String vfModuleId = getChildText(root, 'vfModuleId')
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)
161 vnfAdapterMethod = 'DELETE'
162 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
163 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
165 } else if ('rollbackVfModuleRequest'.equals(requestType)) {
166 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
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)
174 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
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)
182 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
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)
190 vnfAdapterMethod = 'DELETE'
191 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
192 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
194 } else if ('createVolumeGroupRequest'.equals(requestType)) {
195 vnfAdapterMethod = 'POST'
196 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
197 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
199 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
201 } else if ('updateVolumeGroupRequest'.equals(requestType)) {
202 String volumeGroupId = getChildText(root, 'volumeGroupId')
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)
210 vnfAdapterMethod = 'PUT'
211 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
212 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
214 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
216 } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
217 String volumeGroupId = getChildText(root, 'volumeGroupId')
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)
225 vnfAdapterMethod = 'DELETE'
226 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
227 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
229 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
231 } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
232 String volumeGroupId = getVolumeGroupIdFromRollbackRequest(root)
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)
240 vnfAdapterMethod = 'DELETE'
241 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
242 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
244 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8') + '/rollback'
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)
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)
259 // Get the Basic Auth credentials for the VnfAdapter
261 String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth", execution)
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, "");
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, "");
274 } catch (BpmnError e) {
275 msoLogger.debug(" Rethrowing MSOWorkflowException")
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, "");
281 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
285 public String getVolumeGroupIdFromRollbackRequest(Node root) {
286 return root.'volumeGroupRollback'.'volumeGroupId'.text()
289 public String getMessageIdForVolumeGroupRollback(Node root) {
290 return root.'volumeGroupRollback'.'messageId'.text()
294 * This method is used instead of an HTTP Connector task because the
295 * connector does not allow DELETE with a body.
297 public void sendRequestToVnfAdapter(DelegateExecution execution) {
298 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
299 'execution=' + execution.getId() +
301 msoLogger.trace('Entered ' + method)
303 String prefix = execution.getVariable('prefix')
306 String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
307 String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
308 String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
310 RESTConfig config = new RESTConfig(vnfAdapterUrl)
311 RESTClient client = new RESTClient(config).
312 addHeader("Content-Type", "application/xml").
313 addAuthorizationHeader(execution.getVariable(prefix + "basicAuthHeaderValue"));
315 APIResponse response;
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)
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)
331 execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatusCode())
332 execution.setVariable(prefix + "vnfAdapterResponse", response.getResponseBodyAsString())
333 } catch (BpmnError 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)
342 public void processCallback(DelegateExecution execution){
343 def method = getClass().getSimpleName() + '.processCallback(' +
344 'execution=' + execution.getId() +
346 msoLogger.trace('Entered ' + method)
348 String callback = execution.getVariable('VNFAResponse_MESSAGE')
351 msoLogger.debug(getProcessKey(execution) + ": received callback:\n" + callback)
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)
359 Node root = new XmlParser().parseText(callback)
360 if (root.name().endsWith('Exception')) {
361 vnfAdapterWorkflowException(execution, callback)
363 } catch (Exception e) {
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)
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.
377 public void vnfAdapterWorkflowException(DelegateExecution execution, Object response) {
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)
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
400 private Node getChild(Node node, String name) {
401 for (Node child : node.children()) {
402 if (child.name() == name) {
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
415 private String getChildText(Node node, String name) {
416 Node child = getChild(node, name)
417 return child == null ? null : child.text()