2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (c) 2019 Samsung
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
23 package org.onap.so.bpmn.common.scripts
25 import org.onap.so.client.HttpClientFactory
27 import javax.ws.rs.core.Response
28 import org.apache.commons.lang3.*
29 import org.camunda.bpm.engine.delegate.BpmnError
30 import org.camunda.bpm.engine.delegate.DelegateExecution
31 import org.onap.so.bpmn.core.UrnPropertiesReader
32 import org.onap.so.client.HttpClient
33 import org.onap.so.logger.MessageEnum
34 import org.onap.so.logger.MsoLogger
35 import org.slf4j.Logger
36 import org.slf4j.LoggerFactory
37 import org.onap.so.utils.TargetEntity
43 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
44 private static final Logger logger = LoggerFactory.getLogger( VnfAdapterRestV1.class);
47 ExceptionUtil exceptionUtil = new ExceptionUtil()
49 // VNF Response Processing
50 public void preProcessRequest (DelegateExecution execution) {
51 def method = getClass().getSimpleName() + '.preProcessRequest(' +
52 'execution=' + execution.getId() +
54 logger.trace('Entered ' + method)
57 execution.setVariable("prefix", prefix)
58 setSuccessIndicator(execution, false)
61 String request = validateRequest(execution, "mso-request-id")
63 // Get the request type (the name of the root element) from the request
65 Node root = new XmlParser().parseText(request)
66 String requestType = root.name()
67 execution.setVariable(prefix + 'requestType', requestType)
68 logger.debug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType)
70 logger.debug('VnfAdapterRestV1, request: ' + request)
71 // Get the messageId from the request
73 String messageId = getChildText(root, 'messageId')
75 if ('rollbackVolumeGroupRequest'.equals(requestType)) {
76 messageId = getMessageIdForVolumeGroupRollback(root)
79 if (messageId == null || messageId.isEmpty()) {
80 String msg = getProcessKey(execution) + ': no messageId in ' + requestType
81 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
82 MsoLogger.ErrorCode.UnknownError.getValue());
83 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
86 execution.setVariable('VNFAResponse_CORRELATOR', messageId)
87 logger.debug(getProcessKey(execution) + ': VNFAResponse_CORRELATOR = ' + messageId)
89 // Get the notificationUrl from the request
91 String notificationUrl = getChildText(root, 'notificationUrl')
93 if (notificationUrl == null || notificationUrl.isEmpty()) {
94 String msg = getProcessKey(execution) + ': no notificationUrl in ' + requestType
95 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
96 MsoLogger.ErrorCode.UnknownError.getValue());
97 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
100 execution.setVariable(prefix + 'notificationUrl', notificationUrl)
101 logger.debug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl)
103 // Determine the VnfAdapter endpoint
105 String vnfAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.vnf.rest.endpoint", execution)
107 if (vnfAdapterEndpoint == null || vnfAdapterEndpoint.isEmpty()) {
108 String msg = getProcessKey(execution) + ': mso:adapters:vnf:rest:endpoint URN mapping is not defined'
109 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
110 MsoLogger.ErrorCode.UnknownError.getValue());
111 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
114 while (vnfAdapterEndpoint.endsWith('/')) {
115 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
118 String vnfAdapterMethod = null
119 String vnfAdapterUrl = null
120 String vnfAdapterRequest = request
122 if ('createVfModuleRequest'.equals(requestType)) {
123 String vnfId = getChildText(root, 'vnfId')
125 if (vnfId == null || vnfId.isEmpty()) {
126 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
127 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
128 MsoLogger.ErrorCode.UnknownError.getValue());
129 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
132 vnfAdapterMethod = 'POST'
133 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
135 } else if ('updateVfModuleRequest'.equals(requestType)) {
136 String vnfId = getChildText(root, 'vnfId')
138 if (vnfId == null || vnfId.isEmpty()) {
139 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
140 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
141 MsoLogger.ErrorCode.UnknownError.getValue());
142 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
145 String vfModuleId = getChildText(root, 'vfModuleId')
147 if (vfModuleId == null || vfModuleId.isEmpty()) {
148 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
149 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
150 MsoLogger.ErrorCode.UnknownError.getValue());
151 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
154 vnfAdapterMethod = 'PUT'
155 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
156 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
158 } else if ('deleteVfModuleRequest'.equals(requestType)) {
159 String vnfId = getChildText(root, 'vnfId')
161 if (vnfId == null || vnfId.isEmpty()) {
162 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
163 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
164 MsoLogger.ErrorCode.UnknownError.getValue());
165 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
168 String vfModuleId = getChildText(root, 'vfModuleId')
170 if (vfModuleId == null || vfModuleId.isEmpty()) {
171 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
172 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
173 MsoLogger.ErrorCode.UnknownError.getValue());
174 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
177 vnfAdapterMethod = 'DELETE'
178 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
179 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
181 } else if ('rollbackVfModuleRequest'.equals(requestType)) {
182 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
184 if (vfModuleRollbackNode == null) {
185 String msg = getProcessKey(execution) + ': no vfModuleRollback in ' + requestType
186 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
187 MsoLogger.ErrorCode.UnknownError.getValue());
188 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
191 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
193 if (vnfId == null || vnfId.isEmpty()) {
194 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
195 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
196 MsoLogger.ErrorCode.UnknownError.getValue());
197 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
200 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
202 if (vfModuleId == null || vfModuleId.isEmpty()) {
203 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
204 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
205 MsoLogger.ErrorCode.UnknownError.getValue());
206 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
209 vnfAdapterMethod = 'DELETE'
210 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
211 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
213 } else if ('createVolumeGroupRequest'.equals(requestType)) {
214 vnfAdapterMethod = 'POST'
215 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
216 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
218 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
220 } else if ('updateVolumeGroupRequest'.equals(requestType)) {
221 String volumeGroupId = getChildText(root, 'volumeGroupId')
223 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
224 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
225 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
226 MsoLogger.ErrorCode.UnknownError.getValue());
227 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
230 vnfAdapterMethod = 'PUT'
231 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
232 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
234 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
236 } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
237 String volumeGroupId = getChildText(root, 'volumeGroupId')
239 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
240 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
241 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
242 MsoLogger.ErrorCode.UnknownError.getValue());
243 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
246 vnfAdapterMethod = 'DELETE'
247 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
248 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
250 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
252 } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
253 String volumeGroupId = getVolumeGroupIdFromRollbackRequest(root)
255 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
256 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
257 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
258 MsoLogger.ErrorCode.UnknownError.getValue());
259 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
262 vnfAdapterMethod = 'DELETE'
263 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
264 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
266 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8') + '/rollback'
269 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
270 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
271 MsoLogger.ErrorCode.UnknownError.getValue());
272 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
275 execution.setVariable(prefix + 'vnfAdapterMethod', vnfAdapterMethod)
276 logger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterMethod = ' + vnfAdapterMethod)
277 execution.setVariable(prefix + 'vnfAdapterUrl', vnfAdapterUrl)
278 logger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterUrl = ' + vnfAdapterUrl)
279 execution.setVariable(prefix + 'vnfAdapterRequest', vnfAdapterRequest)
280 logger.debug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterRequest = \n' + vnfAdapterRequest)
282 // Get the Basic Auth credentials for the VnfAdapter
284 String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth", execution)
286 if (basicAuthValue == null || basicAuthValue.isEmpty()) {
287 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
288 getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined", "BPMN",
289 MsoLogger.ErrorCode.UnknownError.getValue());
292 def encodedString = utils.getBasicAuth(basicAuthValue, UrnPropertiesReader.getVariable("mso.msoKey", execution))
293 execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
294 } catch (IOException ex) {
295 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
296 getProcessKey(execution) + ": Unable to encode BasicAuth credentials for VnfAdapter",
297 "BPMN", MsoLogger.ErrorCode.UnknownError.getValue());
301 } catch (BpmnError e) {
302 logger.debug(" Rethrowing MSOWorkflowException")
304 } catch (Exception e) {
305 String msg = 'Caught exception in ' + method + ": " + e
306 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
307 MsoLogger.ErrorCode.UnknownError.getValue());
309 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
313 public String getVolumeGroupIdFromRollbackRequest(Node root) {
314 return root.'volumeGroupRollback'.'volumeGroupId'.text()
317 public String getMessageIdForVolumeGroupRollback(Node root) {
318 return root.'volumeGroupRollback'.'messageId'.text()
322 * This method is used instead of an HTTP Connector task because the
323 * connector does not allow DELETE with a body.
325 public void sendRequestToVnfAdapter(DelegateExecution execution) {
326 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
327 'execution=' + execution.getId() +
329 logger.trace('Entered ' + method)
331 String prefix = execution.getVariable('prefix')
334 String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
335 String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
336 String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
338 URL url = new URL(vnfAdapterUrl);
340 HttpClient httpClient = new HttpClientFactory().newXmlClient(url, TargetEntity.VNF_ADAPTER)
341 httpClient.addAdditionalHeader("Authorization", execution.getVariable(prefix + "basicAuthHeaderValue"))
343 httpClient.addAdditionalHeader("X-ONAP-RequestID", execution.getVariable("mso-request-id"))
344 httpClient.addAdditionalHeader("X-ONAP-InvocationID", UUID.randomUUID().toString())
345 httpClient.addAdditionalHeader("X-ONAP-PartnerName", "SO-VNFAdapter")
348 if ("GET".equals(vnfAdapterMethod)) {
349 response = httpClient.get()
350 } else if ("PUT".equals(vnfAdapterMethod)) {
351 response = httpClient.put(vnfAdapterRequest)
352 } else if ("POST".equals(vnfAdapterMethod)) {
353 response = httpClient.post(vnfAdapterRequest)
354 } else if ("DELETE".equals(vnfAdapterMethod)) {
355 response = httpClient.delete(vnfAdapterRequest)
357 String msg = 'Unsupported HTTP method "' + vnfAdapterMethod + '" in ' + method + ": " + e
358 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
359 MsoLogger.ErrorCode.UnknownError.getValue());
360 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
363 execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatus())
364 if(response.hasEntity()){
365 execution.setVariable(prefix + "vnfAdapterResponse", response.readEntity(String.class))
367 } catch (BpmnError e) {
369 } catch (Exception e) {
370 String msg = 'Caught exception in ' + method + ": " + e
371 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
372 MsoLogger.ErrorCode.UnknownError.getValue());
373 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
377 public void processCallback(DelegateExecution execution){
378 def method = getClass().getSimpleName() + '.processCallback(' +
379 'execution=' + execution.getId() +
381 logger.trace('Entered ' + method)
383 String callback = execution.getVariable('VNFAResponse_MESSAGE')
386 logger.debug(getProcessKey(execution) + ": received callback:\n" + callback)
388 // The XML callback is available to the calling flow in any case,
389 // even if a WorkflowException is generated.
390 execution.setVariable(getProcessKey(execution) + 'Response', callback)
391 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead.
392 execution.setVariable("WorkflowResponse", callback)
394 callback = utils.removeXmlPreamble(callback)
396 Node root = new XmlParser().parseText(callback)
397 if (root.name().endsWith('Exception')) {
398 vnfAdapterWorkflowException(execution, callback)
400 } catch (Exception e) {
401 logger.debug("Error encountered within VnfAdapterRest ProcessCallback method", e)
402 exceptionUtil.buildAndThrowWorkflowException(execution, 7020, "Error encountered within VnfAdapterRest ProcessCallback method")
407 * Tries to parse the response as XML to extract the information to create
408 * a WorkflowException. If the response cannot be parsed, a more generic
409 * WorkflowException is created.
411 public void vnfAdapterWorkflowException(DelegateExecution execution, Object response) {
413 Node root = new XmlParser().parseText(response)
414 String category = getChildText(root, "category")
415 category = category == null || category.isEmpty() ? "" : " category='" + category + "'"
416 String message = getChildText(root, "message")
417 message = message == null || message.isEmpty() ? "" : " message='" + message + "'"
418 String rolledBack = getChildText(root, "rolledBack")
419 rolledBack = rolledBack == null || rolledBack.isEmpty() ? "" : " rolledBack='" + rolledBack + "'"
420 exceptionUtil.buildWorkflowException(execution, 7020, "Received " + root.name() +
421 " from VnfAdapter:" + category + message + rolledBack);
422 } catch (Exception e) {
423 response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
424 exceptionUtil.buildWorkflowException(execution, 7020, "Received error from VnfAdapter: " + response)
429 * Gets the named child of the specified node.
430 * @param node the node
431 * @param name the child name
432 * @return the child node, or null if no such child exists
434 private Node getChild(Node node, String name) {
435 for (Node child : node.children()) {
436 if (child.name() == name) {
444 * Gets the text of the named child of the specified node.
445 * @param node the node
446 * @param name the child name
447 * @return the child node text, or null if no such child exists
449 private String getChildText(Node node, String name) {
450 Node child = getChild(node, name)
451 return child == null ? null : child.text()