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
26 import org.onap.so.logger.ErrorCode
28 import javax.ws.rs.core.Response
29 import org.apache.commons.lang3.*
30 import org.camunda.bpm.engine.delegate.BpmnError
31 import org.camunda.bpm.engine.delegate.DelegateExecution
32 import org.onap.so.bpmn.core.UrnPropertiesReader
33 import org.onap.so.client.HttpClient
34 import org.onap.so.logger.MessageEnum
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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", 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 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 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 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()