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 com.att.bpm.scripts
23 import groovy.xml.XmlUtil
25 import java.text.SimpleDateFormat
26 import java.net.URLEncoder
28 import org.apache.commons.codec.binary.Base64
29 import org.apache.commons.lang3.*
30 import org.camunda.bpm.engine.delegate.BpmnError
31 import org.camunda.bpm.engine.runtime.Execution
33 import org.openecomp.mso.bpmn.core.WorkflowException
34 import org.openecomp.mso.rest.APIResponse
35 import org.openecomp.mso.rest.RESTClient
36 import org.openecomp.mso.rest.RESTConfig
38 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
40 ExceptionUtil exceptionUtil = new ExceptionUtil()
42 // VNF Response Processing
43 public void preProcessRequest (Execution execution) {
44 def method = getClass().getSimpleName() + '.preProcessRequest(' +
45 'execution=' + execution.getId() +
47 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
48 logDebug('Entered ' + method, isDebugLogEnabled)
51 execution.setVariable("prefix", prefix)
52 setSuccessIndicator(execution, false)
55 String request = validateRequest(execution, "att-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 logDebug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType, isDebugLogEnabled)
64 utils.logAudit('VnfAdapterRestV1, request: ' + request)
65 // Get the messageId from the request
67 String messageId = getChildText(root, 'messageId')
69 if (messageId == null || messageId.isEmpty()) {
70 String msg = getProcessKey(execution) + ': no messageId in ' + requestType
72 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
75 execution.setVariable(prefix + 'messageId', messageId)
76 logDebug(getProcessKey(execution) + ': ' + prefix + 'messageId = ' + messageId, isDebugLogEnabled)
78 // Get the notificationUrl from the request
80 String notificationUrl = getChildText(root, 'notificationUrl')
82 if (notificationUrl == null || notificationUrl.isEmpty()) {
83 String msg = getProcessKey(execution) + ': no notificationUrl in ' + requestType
85 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
88 execution.setVariable(prefix + 'notificationUrl', notificationUrl)
89 logDebug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl, isDebugLogEnabled)
91 // Determine the VnfAdapter endpoint
93 String vnfAdapterEndpoint = execution.getVariable("URN_mso_adapters_vnf_rest_endpoint")
95 if (vnfAdapterEndpoint == null || vnfAdapterEndpoint.isEmpty()) {
96 String msg = getProcessKey(execution) + ': mso:adapters:vnf:rest:endpoint URN mapping is not defined'
98 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
101 while (vnfAdapterEndpoint.endsWith('/')) {
102 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
105 String vnfAdapterMethod = null
106 String vnfAdapterUrl = null
107 String vnfAdapterRequest = request
109 if ('createVfModuleRequest'.equals(requestType)) {
110 String vnfId = getChildText(root, 'vnfId')
112 if (vnfId == null || vnfId.isEmpty()) {
113 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
115 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
118 vnfAdapterMethod = 'POST'
119 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
121 } else if ('updateVfModuleRequest'.equals(requestType)) {
122 String vnfId = getChildText(root, 'vnfId')
124 if (vnfId == null || vnfId.isEmpty()) {
125 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
127 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
130 String vfModuleId = getChildText(root, 'vfModuleId')
132 if (vfModuleId == null || vfModuleId.isEmpty()) {
133 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
135 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
138 vnfAdapterMethod = 'PUT'
139 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
140 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
142 } else if ('deleteVfModuleRequest'.equals(requestType)) {
143 String vnfId = getChildText(root, 'vnfId')
145 if (vnfId == null || vnfId.isEmpty()) {
146 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
148 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
151 String vfModuleId = getChildText(root, 'vfModuleId')
153 if (vfModuleId == null || vfModuleId.isEmpty()) {
154 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
156 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
159 vnfAdapterMethod = 'DELETE'
160 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
161 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
163 } else if ('rollbackVfModuleRequest'.equals(requestType)) {
164 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
166 if (vfModuleRollbackNode == null) {
167 String msg = getProcessKey(execution) + ': no vfModuleRollback in ' + requestType
169 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
172 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
174 if (vnfId == null || vnfId.isEmpty()) {
175 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
177 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
180 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
182 if (vfModuleId == null || vfModuleId.isEmpty()) {
183 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
185 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
188 vnfAdapterMethod = 'DELETE'
189 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
190 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
192 } else if ('createVolumeGroupRequest'.equals(requestType)) {
193 vnfAdapterMethod = 'POST'
194 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
195 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
197 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
199 } else if ('updateVolumeGroupRequest'.equals(requestType)) {
200 String volumeGroupId = getChildText(root, 'volumeGroupId')
202 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
203 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
205 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
208 vnfAdapterMethod = 'PUT'
209 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
210 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
212 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
214 } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
215 String volumeGroupId = getChildText(root, 'volumeGroupId')
217 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
218 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
220 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
223 vnfAdapterMethod = 'DELETE'
224 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
225 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
227 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
229 } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
230 String volumeGroupId = getChildText(root, 'volumeGroupId')
232 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
233 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
235 createWorkflowException(execution, 2000, msg)
238 vnfAdapterMethod = 'DELETE'
239 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
240 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
242 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8') + '/rollback'
245 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
247 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
250 execution.setVariable(prefix + 'vnfAdapterMethod', vnfAdapterMethod)
251 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterMethod = ' + vnfAdapterMethod, isDebugLogEnabled)
252 execution.setVariable(prefix + 'vnfAdapterUrl', vnfAdapterUrl)
253 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterUrl = ' + vnfAdapterUrl, isDebugLogEnabled)
254 execution.setVariable(prefix + 'vnfAdapterRequest', vnfAdapterRequest)
255 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterRequest = \n' + vnfAdapterRequest, isDebugLogEnabled)
257 // Get the Basic Auth credentials for the VnfAdapter
259 String basicAuthValue = execution.getVariable("URN_mso_adapters_po_auth")
261 if (basicAuthValue == null || basicAuthValue.isEmpty()) {
262 logError(getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined")
264 logDebug(getProcessKey(execution) + ": Obtained BasicAuth credentials for VnfAdapter:" +
265 basicAuthValue, isDebugLogEnabled)
267 def encodedString = utils.getBasicAuth(basicAuthValue, execution.getVariable("URN_mso_msoKey"))
268 execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
269 } catch (IOException ex) {
270 logError(getProcessKey(execution) + ": Unable to encode BasicAuth credentials for VnfAdapter")
274 } catch (BpmnError e) {
275 logDebug(" Rethrowing MSOWorkflowException", isDebugLogEnabled)
277 } catch (Exception e) {
278 String msg = 'Caught exception in ' + method + ": " + e
280 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
285 * This method is used instead of an HTTP Connector task because the
286 * connector does not allow DELETE with a body.
288 public void sendRequestToVnfAdapter(Execution execution) {
289 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
290 'execution=' + execution.getId() +
292 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
293 logDebug('Entered ' + method, isDebugLogEnabled)
295 String prefix = execution.getVariable('prefix')
298 String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
299 String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
300 String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
302 RESTConfig config = new RESTConfig(vnfAdapterUrl)
303 RESTClient client = new RESTClient(config).
304 addHeader("Content-Type", "application/xml").
305 addAuthorizationHeader(execution.getVariable(prefix + "basicAuthHeaderValue"));
307 APIResponse response;
309 if ("GET".equals(vnfAdapterMethod)) {
310 response = client.httpGet()
311 } else if ("PUT".equals(vnfAdapterMethod)) {
312 response = client.httpPut(vnfAdapterRequest)
313 } else if ("POST".equals(vnfAdapterMethod)) {
314 response = client.httpPost(vnfAdapterRequest)
315 } else if ("DELETE".equals(vnfAdapterMethod)) {
316 response = client.httpDelete(vnfAdapterRequest)
318 String msg = 'Unsupported HTTP method "' + vnfAdapterMethod + '" in ' + method + ": " + e
320 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
323 execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatusCode())
324 execution.setVariable(prefix + "vnfAdapterResponse", response.getResponseBodyAsString())
325 } catch (BpmnError e) {
327 } catch (Exception e) {
328 String msg = 'Caught exception in ' + method + ": " + e
330 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
334 public void processCallback(Execution execution){
335 def method = getClass().getSimpleName() + '.processCallback(' +
336 'execution=' + execution.getId() +
338 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
339 logDebug('Entered ' + method, isDebugLogEnabled)
341 String prefix = execution.getVariable('prefix')
342 String callback = execution.getVariable(prefix + 'callback')
345 logDebug(getProcessKey(execution) + ": received callback:\n" + callback, isDebugLogEnabled)
347 Node root = new XmlParser().parseText(callback)
348 if (root.name().endsWith('Exception')) {
349 vnfAdapterWorkflowException(execution, callback)
352 // The XML callback is available to the calling flow in any case,
353 // even if a WorkflowException was generated.
354 execution.setVariable(getProcessKey(execution) + 'Response', callback)
355 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead.
356 execution.setVariable("WorkflowResponse", callback)
357 } catch(BpmnError b){
359 } catch (Exception e) {
361 callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
362 String msg = "Received error from VnfAdapter: " + callback
363 logDebug(getProcessKey(execution) + ': ' + msg, isDebugLogEnabled)
364 exceptionUtil.buildAndThrowWorkflowException(execution, 7020, msg)
369 * Tries to parse the response as XML to extract the information to create
370 * a WorkflowException. If the response cannot be parsed, a more generic
371 * WorkflowException is created.
373 public void vnfAdapterWorkflowException(Execution execution, Object response) {
375 Node root = new XmlParser().parseText(response)
376 String category = getChildText(root, "category")
377 category = category == null || category.isEmpty() ? "" : " category='" + category + "'"
378 String message = getChildText(root, "message")
379 message = message == null || message.isEmpty() ? "" : " message='" + message + "'"
380 String rolledBack = getChildText(root, "rolledBack")
381 rolledBack = rolledBack == null || rolledBack.isEmpty() ? "" : " rolledBack='" + rolledBack + "'"
382 exceptionUtil.buildAndThrowWorkflowException(execution, 7020, "Received " + root.name() +
383 " from VnfAdapter:" + category + message + rolledBack);
386 }catch (Exception e) {
387 response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
388 exceptionUtil.buildAndThrowWorkflowException(execution, 7020, "Received error from VnfAdapter: " + response)
393 * Gets the named child of the specified node.
394 * @param node the node
395 * @param name the child name
396 * @return the child node, or null if no such child exists
398 private Node getChild(Node node, String name) {
399 for (Node child : node.children()) {
400 if (child.name() == name) {
408 * Gets the text of the named child of the specified node.
409 * @param node the node
410 * @param name the child name
411 * @return the child node text, or null if no such child exists
413 private String getChildText(Node node, String name) {
414 Node child = getChild(node, name)
415 return child == null ? null : child.text()