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 javax.ws.rs.core.Response
24 import org.apache.commons.lang3.*
25 import org.camunda.bpm.engine.delegate.BpmnError
26 import org.camunda.bpm.engine.delegate.DelegateExecution
27 import org.onap.so.bpmn.core.UrnPropertiesReader
28 import org.onap.so.client.HttpClient
29 import org.onap.so.logger.MessageEnum
30 import org.onap.so.logger.MsoLogger
31 import org.onap.so.utils.TargetEntity
37 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
38 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, VnfAdapterRestV1.class);
41 ExceptionUtil exceptionUtil = new ExceptionUtil()
43 // VNF Response Processing
44 public void preProcessRequest (DelegateExecution execution) {
45 def method = getClass().getSimpleName() + '.preProcessRequest(' +
46 'execution=' + execution.getId() +
48 msoLogger.trace('Entered ' + method)
51 execution.setVariable("prefix", prefix)
52 setSuccessIndicator(execution, false)
55 String request = validateRequest(execution, "mso-request-id")
57 // Get the request type (the name of the root element) from the request
59 Node root = new XmlParser().parseText(request)
60 String requestType = root.name()
61 execution.setVariable(prefix + 'requestType', requestType)
62 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType)
64 msoLogger.debug('VnfAdapterRestV1, request: ' + request)
65 // Get the messageId from the request
67 String messageId = getChildText(root, 'messageId')
69 if ('rollbackVolumeGroupRequest'.equals(requestType)) {
70 messageId = getMessageIdForVolumeGroupRollback(root)
73 if (messageId == null || messageId.isEmpty()) {
74 String msg = getProcessKey(execution) + ': no messageId in ' + requestType
75 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
76 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
79 execution.setVariable('VNFAResponse_CORRELATOR', messageId)
80 msoLogger.debug(getProcessKey(execution) + ': VNFAResponse_CORRELATOR = ' + messageId)
82 // Get the notificationUrl from the request
84 String notificationUrl = getChildText(root, 'notificationUrl')
86 if (notificationUrl == null || notificationUrl.isEmpty()) {
87 String msg = getProcessKey(execution) + ': no notificationUrl in ' + requestType
88 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
89 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
92 execution.setVariable(prefix + 'notificationUrl', notificationUrl)
93 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl)
95 // Determine the VnfAdapter endpoint
97 String vnfAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.vnf.rest.endpoint", execution)
99 if (vnfAdapterEndpoint == null || vnfAdapterEndpoint.isEmpty()) {
100 String msg = getProcessKey(execution) + ': mso:adapters:vnf:rest:endpoint URN mapping is not defined'
101 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
102 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
105 while (vnfAdapterEndpoint.endsWith('/')) {
106 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
109 String vnfAdapterMethod = null
110 String vnfAdapterUrl = null
111 String vnfAdapterRequest = request
113 if ('createVfModuleRequest'.equals(requestType)) {
114 String vnfId = getChildText(root, 'vnfId')
116 if (vnfId == null || vnfId.isEmpty()) {
117 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
118 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
119 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
122 vnfAdapterMethod = 'POST'
123 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
125 } else if ('updateVfModuleRequest'.equals(requestType)) {
126 String vnfId = getChildText(root, 'vnfId')
128 if (vnfId == null || vnfId.isEmpty()) {
129 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
130 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
131 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
134 String vfModuleId = getChildText(root, 'vfModuleId')
136 if (vfModuleId == null || vfModuleId.isEmpty()) {
137 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
138 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
139 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
142 vnfAdapterMethod = 'PUT'
143 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
144 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
146 } else if ('deleteVfModuleRequest'.equals(requestType)) {
147 String vnfId = getChildText(root, 'vnfId')
149 if (vnfId == null || vnfId.isEmpty()) {
150 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
151 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
152 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
155 String vfModuleId = getChildText(root, 'vfModuleId')
157 if (vfModuleId == null || vfModuleId.isEmpty()) {
158 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
159 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
160 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
163 vnfAdapterMethod = 'DELETE'
164 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
165 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
167 } else if ('rollbackVfModuleRequest'.equals(requestType)) {
168 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
170 if (vfModuleRollbackNode == null) {
171 String msg = getProcessKey(execution) + ': no vfModuleRollback in ' + requestType
172 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
173 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
176 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
178 if (vnfId == null || vnfId.isEmpty()) {
179 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
180 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
181 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
184 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
186 if (vfModuleId == null || vfModuleId.isEmpty()) {
187 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
188 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
189 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
192 vnfAdapterMethod = 'DELETE'
193 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
194 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
196 } else if ('createVolumeGroupRequest'.equals(requestType)) {
197 vnfAdapterMethod = 'POST'
198 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
199 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
201 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
203 } else if ('updateVolumeGroupRequest'.equals(requestType)) {
204 String volumeGroupId = getChildText(root, 'volumeGroupId')
206 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
207 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
208 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
209 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
212 vnfAdapterMethod = 'PUT'
213 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
214 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
216 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
218 } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
219 String volumeGroupId = getChildText(root, 'volumeGroupId')
221 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
222 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
223 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
224 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
227 vnfAdapterMethod = 'DELETE'
228 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
229 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
231 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
233 } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
234 String volumeGroupId = getVolumeGroupIdFromRollbackRequest(root)
236 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
237 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
238 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
239 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
242 vnfAdapterMethod = 'DELETE'
243 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
244 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
246 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8') + '/rollback'
249 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
250 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
251 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
254 execution.setVariable(prefix + 'vnfAdapterMethod', vnfAdapterMethod)
255 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterMethod = ' + vnfAdapterMethod)
256 execution.setVariable(prefix + 'vnfAdapterUrl', vnfAdapterUrl)
257 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterUrl = ' + vnfAdapterUrl)
258 execution.setVariable(prefix + 'vnfAdapterRequest', vnfAdapterRequest)
259 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterRequest = \n' + vnfAdapterRequest)
261 // Get the Basic Auth credentials for the VnfAdapter
263 String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth", execution)
265 if (basicAuthValue == null || basicAuthValue.isEmpty()) {
266 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
269 def encodedString = utils.getBasicAuth(basicAuthValue, UrnPropertiesReader.getVariable("mso.msoKey", execution))
270 execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
271 } catch (IOException ex) {
272 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, getProcessKey(execution) + ": Unable to encode BasicAuth credentials for VnfAdapter", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
276 } catch (BpmnError e) {
277 msoLogger.debug(" Rethrowing MSOWorkflowException")
279 } catch (Exception e) {
280 String msg = 'Caught exception in ' + method + ": " + e
281 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
283 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
287 public String getVolumeGroupIdFromRollbackRequest(Node root) {
288 return root.'volumeGroupRollback'.'volumeGroupId'.text()
291 public String getMessageIdForVolumeGroupRollback(Node root) {
292 return root.'volumeGroupRollback'.'messageId'.text()
296 * This method is used instead of an HTTP Connector task because the
297 * connector does not allow DELETE with a body.
299 public void sendRequestToVnfAdapter(DelegateExecution execution) {
300 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
301 'execution=' + execution.getId() +
303 msoLogger.trace('Entered ' + method)
305 String prefix = execution.getVariable('prefix')
308 String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
309 String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
310 String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
312 URL url = new URL(vnfAdapterUrl);
314 HttpClient httpClient = new HttpClient(url, "application/xml", TargetEntity.VNF_ADAPTER)
315 httpClient.addAdditionalHeader("Authorization", execution.getVariable(prefix + "basicAuthHeaderValue"))
317 httpClient.addAdditionalHeader("X-ONAP-RequestID", execution.getVariable("mso-request-id"))
318 httpClient.addAdditionalHeader("X-ONAP-InvocationID", UUID.randomUUID().toString())
319 httpClient.addAdditionalHeader("X-ONAP-PartnerName", "SO-VNFAdapter")
322 if ("GET".equals(vnfAdapterMethod)) {
323 response = httpClient.get()
324 } else if ("PUT".equals(vnfAdapterMethod)) {
325 response = httpClient.put(vnfAdapterRequest)
326 } else if ("POST".equals(vnfAdapterMethod)) {
327 response = httpClient.post(vnfAdapterRequest)
328 } else if ("DELETE".equals(vnfAdapterMethod)) {
329 response = httpClient.delete(vnfAdapterRequest)
331 String msg = 'Unsupported HTTP method "' + vnfAdapterMethod + '" in ' + method + ": " + e
332 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
333 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
336 execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatus())
337 if(response.hasEntity()){
338 execution.setVariable(prefix + "vnfAdapterResponse", response.readEntity(String.class))
340 } catch (BpmnError e) {
342 } catch (Exception e) {
343 String msg = 'Caught exception in ' + method + ": " + e
344 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
345 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
349 public void processCallback(DelegateExecution execution){
350 def method = getClass().getSimpleName() + '.processCallback(' +
351 'execution=' + execution.getId() +
353 msoLogger.trace('Entered ' + method)
355 String callback = execution.getVariable('VNFAResponse_MESSAGE')
358 msoLogger.debug(getProcessKey(execution) + ": received callback:\n" + callback)
360 // The XML callback is available to the calling flow in any case,
361 // even if a WorkflowException is generated.
362 execution.setVariable(getProcessKey(execution) + 'Response', callback)
363 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead.
364 execution.setVariable("WorkflowResponse", callback)
366 Node root = new XmlParser().parseText(callback)
367 if (root.name().endsWith('Exception')) {
368 vnfAdapterWorkflowException(execution, callback)
370 } catch (Exception e) {
372 callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
373 String msg = "Received error from VnfAdapter: " + callback
374 msoLogger.debug(getProcessKey(execution) + ': ' + msg)
375 exceptionUtil.buildWorkflowException(execution, 7020, msg)
380 * Tries to parse the response as XML to extract the information to create
381 * a WorkflowException. If the response cannot be parsed, a more generic
382 * WorkflowException is created.
384 public void vnfAdapterWorkflowException(DelegateExecution execution, Object response) {
386 Node root = new XmlParser().parseText(response)
387 String category = getChildText(root, "category")
388 category = category == null || category.isEmpty() ? "" : " category='" + category + "'"
389 String message = getChildText(root, "message")
390 message = message == null || message.isEmpty() ? "" : " message='" + message + "'"
391 String rolledBack = getChildText(root, "rolledBack")
392 rolledBack = rolledBack == null || rolledBack.isEmpty() ? "" : " rolledBack='" + rolledBack + "'"
393 exceptionUtil.buildWorkflowException(execution, 7020, "Received " + root.name() +
394 " from VnfAdapter:" + category + message + rolledBack);
395 } catch (Exception e) {
396 response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
397 exceptionUtil.buildWorkflowException(execution, 7020, "Received error from VnfAdapter: " + response)
402 * Gets the named child of the specified node.
403 * @param node the node
404 * @param name the child name
405 * @return the child node, or null if no such child exists
407 private Node getChild(Node node, String name) {
408 for (Node child : node.children()) {
409 if (child.name() == name) {
417 * Gets the text of the named child of the specified node.
418 * @param node the node
419 * @param name the child name
420 * @return the child node text, or null if no such child exists
422 private String getChildText(Node node, String name) {
423 Node child = getChild(node, name)
424 return child == null ? null : child.text()