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.onap.so.client.HttpClientFactory
25 import javax.ws.rs.core.Response
26 import org.apache.commons.lang3.*
27 import org.camunda.bpm.engine.delegate.BpmnError
28 import org.camunda.bpm.engine.delegate.DelegateExecution
29 import org.onap.so.bpmn.core.UrnPropertiesReader
30 import org.onap.so.client.HttpClient
31 import org.onap.so.logger.MessageEnum
32 import org.onap.so.logger.MsoLogger
33 import org.onap.so.utils.TargetEntity
39 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
40 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, VnfAdapterRestV1.class);
43 ExceptionUtil exceptionUtil = new ExceptionUtil()
45 // VNF Response Processing
46 public void preProcessRequest (DelegateExecution execution) {
47 def method = getClass().getSimpleName() + '.preProcessRequest(' +
48 'execution=' + execution.getId() +
50 msoLogger.trace('Entered ' + method)
53 execution.setVariable("prefix", prefix)
54 setSuccessIndicator(execution, false)
57 String request = validateRequest(execution, "mso-request-id")
59 // Get the request type (the name of the root element) from the request
61 Node root = new XmlParser().parseText(request)
62 String requestType = root.name()
63 execution.setVariable(prefix + 'requestType', requestType)
64 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType)
66 msoLogger.debug('VnfAdapterRestV1, request: ' + request)
67 // Get the messageId from the request
69 String messageId = getChildText(root, 'messageId')
71 if ('rollbackVolumeGroupRequest'.equals(requestType)) {
72 messageId = getMessageIdForVolumeGroupRollback(root)
75 if (messageId == null || messageId.isEmpty()) {
76 String msg = getProcessKey(execution) + ': no messageId in ' + requestType
77 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
78 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
81 execution.setVariable('VNFAResponse_CORRELATOR', messageId)
82 msoLogger.debug(getProcessKey(execution) + ': VNFAResponse_CORRELATOR = ' + messageId)
84 // Get the notificationUrl from the request
86 String notificationUrl = getChildText(root, 'notificationUrl')
88 if (notificationUrl == null || notificationUrl.isEmpty()) {
89 String msg = getProcessKey(execution) + ': no notificationUrl in ' + requestType
90 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
91 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
94 execution.setVariable(prefix + 'notificationUrl', notificationUrl)
95 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl)
97 // Determine the VnfAdapter endpoint
99 String vnfAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.vnf.rest.endpoint", execution)
101 if (vnfAdapterEndpoint == null || vnfAdapterEndpoint.isEmpty()) {
102 String msg = getProcessKey(execution) + ': mso:adapters:vnf:rest:endpoint URN mapping is not defined'
103 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
104 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
107 while (vnfAdapterEndpoint.endsWith('/')) {
108 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
111 String vnfAdapterMethod = null
112 String vnfAdapterUrl = null
113 String vnfAdapterRequest = request
115 if ('createVfModuleRequest'.equals(requestType)) {
116 String vnfId = getChildText(root, 'vnfId')
118 if (vnfId == null || vnfId.isEmpty()) {
119 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
120 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
121 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
124 vnfAdapterMethod = 'POST'
125 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
127 } else if ('updateVfModuleRequest'.equals(requestType)) {
128 String vnfId = getChildText(root, 'vnfId')
130 if (vnfId == null || vnfId.isEmpty()) {
131 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
132 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
133 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
136 String vfModuleId = getChildText(root, 'vfModuleId')
138 if (vfModuleId == null || vfModuleId.isEmpty()) {
139 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
140 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
141 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
144 vnfAdapterMethod = 'PUT'
145 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
146 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
148 } else if ('deleteVfModuleRequest'.equals(requestType)) {
149 String vnfId = getChildText(root, 'vnfId')
151 if (vnfId == null || vnfId.isEmpty()) {
152 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
153 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
154 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
157 String vfModuleId = getChildText(root, 'vfModuleId')
159 if (vfModuleId == null || vfModuleId.isEmpty()) {
160 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
161 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
162 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
165 vnfAdapterMethod = 'DELETE'
166 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
167 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
169 } else if ('rollbackVfModuleRequest'.equals(requestType)) {
170 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
172 if (vfModuleRollbackNode == null) {
173 String msg = getProcessKey(execution) + ': no vfModuleRollback in ' + requestType
174 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
175 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
178 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
180 if (vnfId == null || vnfId.isEmpty()) {
181 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
182 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
183 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
186 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
188 if (vfModuleId == null || vfModuleId.isEmpty()) {
189 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
190 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
191 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
194 vnfAdapterMethod = 'DELETE'
195 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
196 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
198 } else if ('createVolumeGroupRequest'.equals(requestType)) {
199 vnfAdapterMethod = 'POST'
200 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
201 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
203 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
205 } else if ('updateVolumeGroupRequest'.equals(requestType)) {
206 String volumeGroupId = getChildText(root, 'volumeGroupId')
208 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
209 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
210 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
211 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
214 vnfAdapterMethod = 'PUT'
215 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
216 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
218 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
220 } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
221 String volumeGroupId = getChildText(root, 'volumeGroupId')
223 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
224 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
225 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
226 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
229 vnfAdapterMethod = 'DELETE'
230 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
231 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
233 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
235 } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
236 String volumeGroupId = getVolumeGroupIdFromRollbackRequest(root)
238 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
239 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
240 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
241 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
244 vnfAdapterMethod = 'DELETE'
245 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
246 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
248 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8') + '/rollback'
251 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
252 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
253 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
256 execution.setVariable(prefix + 'vnfAdapterMethod', vnfAdapterMethod)
257 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterMethod = ' + vnfAdapterMethod)
258 execution.setVariable(prefix + 'vnfAdapterUrl', vnfAdapterUrl)
259 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterUrl = ' + vnfAdapterUrl)
260 execution.setVariable(prefix + 'vnfAdapterRequest', vnfAdapterRequest)
261 msoLogger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterRequest = \n' + vnfAdapterRequest)
263 // Get the Basic Auth credentials for the VnfAdapter
265 String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth", execution)
267 if (basicAuthValue == null || basicAuthValue.isEmpty()) {
268 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
271 def encodedString = utils.getBasicAuth(basicAuthValue, UrnPropertiesReader.getVariable("mso.msoKey", execution))
272 execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
273 } catch (IOException ex) {
274 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, getProcessKey(execution) + ": Unable to encode BasicAuth credentials for VnfAdapter", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
278 } catch (BpmnError e) {
279 msoLogger.debug(" Rethrowing MSOWorkflowException")
281 } catch (Exception e) {
282 String msg = 'Caught exception in ' + method + ": " + e
283 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
285 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
289 public String getVolumeGroupIdFromRollbackRequest(Node root) {
290 return root.'volumeGroupRollback'.'volumeGroupId'.text()
293 public String getMessageIdForVolumeGroupRollback(Node root) {
294 return root.'volumeGroupRollback'.'messageId'.text()
298 * This method is used instead of an HTTP Connector task because the
299 * connector does not allow DELETE with a body.
301 public void sendRequestToVnfAdapter(DelegateExecution execution) {
302 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
303 'execution=' + execution.getId() +
305 msoLogger.trace('Entered ' + method)
307 String prefix = execution.getVariable('prefix')
310 String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
311 String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
312 String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
314 URL url = new URL(vnfAdapterUrl);
316 HttpClient httpClient = new HttpClientFactory().newXmlClient(url, TargetEntity.VNF_ADAPTER)
317 httpClient.addAdditionalHeader("Authorization", execution.getVariable(prefix + "basicAuthHeaderValue"))
319 httpClient.addAdditionalHeader("X-ONAP-RequestID", execution.getVariable("mso-request-id"))
320 httpClient.addAdditionalHeader("X-ONAP-InvocationID", UUID.randomUUID().toString())
321 httpClient.addAdditionalHeader("X-ONAP-PartnerName", "SO-VNFAdapter")
324 if ("GET".equals(vnfAdapterMethod)) {
325 response = httpClient.get()
326 } else if ("PUT".equals(vnfAdapterMethod)) {
327 response = httpClient.put(vnfAdapterRequest)
328 } else if ("POST".equals(vnfAdapterMethod)) {
329 response = httpClient.post(vnfAdapterRequest)
330 } else if ("DELETE".equals(vnfAdapterMethod)) {
331 response = httpClient.delete(vnfAdapterRequest)
333 String msg = 'Unsupported HTTP method "' + vnfAdapterMethod + '" in ' + method + ": " + e
334 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
335 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
338 execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatus())
339 if(response.hasEntity()){
340 execution.setVariable(prefix + "vnfAdapterResponse", response.readEntity(String.class))
342 } catch (BpmnError e) {
344 } catch (Exception e) {
345 String msg = 'Caught exception in ' + method + ": " + e
346 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
347 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
351 public void processCallback(DelegateExecution execution){
352 def method = getClass().getSimpleName() + '.processCallback(' +
353 'execution=' + execution.getId() +
355 msoLogger.trace('Entered ' + method)
357 String callback = execution.getVariable('VNFAResponse_MESSAGE')
360 msoLogger.debug(getProcessKey(execution) + ": received callback:\n" + callback)
362 // The XML callback is available to the calling flow in any case,
363 // even if a WorkflowException is generated.
364 execution.setVariable(getProcessKey(execution) + 'Response', callback)
365 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead.
366 execution.setVariable("WorkflowResponse", callback)
368 Node root = new XmlParser().parseText(callback)
369 if (root.name().endsWith('Exception')) {
370 vnfAdapterWorkflowException(execution, callback)
372 } catch (Exception e) {
374 callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
375 String msg = "Received error from VnfAdapter: " + callback
376 msoLogger.debug(getProcessKey(execution) + ': ' + msg)
377 exceptionUtil.buildWorkflowException(execution, 7020, msg)
382 * Tries to parse the response as XML to extract the information to create
383 * a WorkflowException. If the response cannot be parsed, a more generic
384 * WorkflowException is created.
386 public void vnfAdapterWorkflowException(DelegateExecution execution, Object response) {
388 Node root = new XmlParser().parseText(response)
389 String category = getChildText(root, "category")
390 category = category == null || category.isEmpty() ? "" : " category='" + category + "'"
391 String message = getChildText(root, "message")
392 message = message == null || message.isEmpty() ? "" : " message='" + message + "'"
393 String rolledBack = getChildText(root, "rolledBack")
394 rolledBack = rolledBack == null || rolledBack.isEmpty() ? "" : " rolledBack='" + rolledBack + "'"
395 exceptionUtil.buildWorkflowException(execution, 7020, "Received " + root.name() +
396 " from VnfAdapter:" + category + message + rolledBack);
397 } catch (Exception e) {
398 response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
399 exceptionUtil.buildWorkflowException(execution, 7020, "Received error from VnfAdapter: " + response)
404 * Gets the named child of the specified node.
405 * @param node the node
406 * @param name the child name
407 * @return the child node, or null if no such child exists
409 private Node getChild(Node node, String name) {
410 for (Node child : node.children()) {
411 if (child.name() == name) {
419 * Gets the text of the named child of the specified node.
420 * @param node the node
421 * @param name the child name
422 * @return the child node text, or null if no such child exists
424 private String getChildText(Node node, String name) {
425 Node child = getChild(node, name)
426 return child == null ? null : child.text()