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.openecomp.mso.bpmn.common.scripts
23 import org.apache.commons.lang3.*
24 import org.camunda.bpm.engine.delegate.BpmnError
25 import org.camunda.bpm.engine.runtime.Execution
26 import org.openecomp.mso.rest.APIResponse
27 import org.openecomp.mso.rest.RESTClient
28 import org.openecomp.mso.rest.RESTConfig
30 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
32 ExceptionUtil exceptionUtil = new ExceptionUtil()
34 // VNF Response Processing
35 public void preProcessRequest (Execution execution) {
36 def method = getClass().getSimpleName() + '.preProcessRequest(' +
37 'execution=' + execution.getId() +
39 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
40 logDebug('Entered ' + method, isDebugLogEnabled)
43 execution.setVariable("prefix", prefix)
44 setSuccessIndicator(execution, false)
47 String request = validateRequest(execution, "mso-request-id")
49 // Get the request type (the name of the root element) from the request
51 Node root = new XmlParser().parseText(request)
52 String requestType = root.name()
53 execution.setVariable(prefix + 'requestType', requestType)
54 logDebug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType, isDebugLogEnabled)
56 utils.logAudit('VnfAdapterRestV1, request: ' + request)
57 // Get the messageId from the request
59 String messageId = getChildText(root, 'messageId')
61 if (messageId == null || messageId.isEmpty()) {
62 String msg = getProcessKey(execution) + ': no messageId in ' + requestType
64 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
67 execution.setVariable('VNFAResponse_CORRELATOR', messageId)
68 logDebug(getProcessKey(execution) + ': VNFAResponse_CORRELATOR = ' + messageId, isDebugLogEnabled)
70 // Get the notificationUrl from the request
72 String notificationUrl = getChildText(root, 'notificationUrl')
74 if (notificationUrl == null || notificationUrl.isEmpty()) {
75 String msg = getProcessKey(execution) + ': no notificationUrl in ' + requestType
77 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
80 execution.setVariable(prefix + 'notificationUrl', notificationUrl)
81 logDebug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl, isDebugLogEnabled)
83 // Determine the VnfAdapter endpoint
85 String vnfAdapterEndpoint = execution.getVariable("URN_mso_adapters_vnf_rest_endpoint")
87 if (vnfAdapterEndpoint == null || vnfAdapterEndpoint.isEmpty()) {
88 String msg = getProcessKey(execution) + ': mso:adapters:vnf:rest:endpoint URN mapping is not defined'
90 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
93 while (vnfAdapterEndpoint.endsWith('/')) {
94 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
97 String vnfAdapterMethod = null
98 String vnfAdapterUrl = null
99 String vnfAdapterRequest = request
101 if ('createVfModuleRequest'.equals(requestType)) {
102 String vnfId = getChildText(root, 'vnfId')
104 if (vnfId == null || vnfId.isEmpty()) {
105 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
107 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
110 vnfAdapterMethod = 'POST'
111 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
113 } else if ('updateVfModuleRequest'.equals(requestType)) {
114 String vnfId = getChildText(root, 'vnfId')
116 if (vnfId == null || vnfId.isEmpty()) {
117 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
119 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
122 String vfModuleId = getChildText(root, 'vfModuleId')
124 if (vfModuleId == null || vfModuleId.isEmpty()) {
125 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
127 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
130 vnfAdapterMethod = 'PUT'
131 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
132 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
134 } else if ('deleteVfModuleRequest'.equals(requestType)) {
135 String vnfId = getChildText(root, 'vnfId')
137 if (vnfId == null || vnfId.isEmpty()) {
138 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
140 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
143 String vfModuleId = getChildText(root, 'vfModuleId')
145 if (vfModuleId == null || vfModuleId.isEmpty()) {
146 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
148 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
151 vnfAdapterMethod = 'DELETE'
152 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
153 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
155 } else if ('rollbackVfModuleRequest'.equals(requestType)) {
156 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
158 if (vfModuleRollbackNode == null) {
159 String msg = getProcessKey(execution) + ': no vfModuleRollback in ' + requestType
161 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
164 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
166 if (vnfId == null || vnfId.isEmpty()) {
167 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
169 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
172 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
174 if (vfModuleId == null || vfModuleId.isEmpty()) {
175 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
177 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
180 vnfAdapterMethod = 'DELETE'
181 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
182 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
184 } else if ('createVolumeGroupRequest'.equals(requestType)) {
185 vnfAdapterMethod = 'POST'
186 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
187 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
189 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
191 } else if ('updateVolumeGroupRequest'.equals(requestType)) {
192 String volumeGroupId = getChildText(root, 'volumeGroupId')
194 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
195 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
197 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
200 vnfAdapterMethod = 'PUT'
201 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
202 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
204 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
206 } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
207 String volumeGroupId = getChildText(root, 'volumeGroupId')
209 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
210 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
212 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
215 vnfAdapterMethod = 'DELETE'
216 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
217 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
219 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
221 } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
222 String volumeGroupId = getChildText(root, 'volumeGroupId')
224 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
225 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
227 createWorkflowException(execution, 2000, msg)
230 vnfAdapterMethod = 'DELETE'
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') + '/rollback'
237 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
239 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
242 execution.setVariable(prefix + 'vnfAdapterMethod', vnfAdapterMethod)
243 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterMethod = ' + vnfAdapterMethod, isDebugLogEnabled)
244 execution.setVariable(prefix + 'vnfAdapterUrl', vnfAdapterUrl)
245 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterUrl = ' + vnfAdapterUrl, isDebugLogEnabled)
246 execution.setVariable(prefix + 'vnfAdapterRequest', vnfAdapterRequest)
247 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterRequest = \n' + vnfAdapterRequest, isDebugLogEnabled)
249 // Get the Basic Auth credentials for the VnfAdapter
251 String basicAuthValue = execution.getVariable("URN_mso_adapters_po_auth")
253 if (basicAuthValue == null || basicAuthValue.isEmpty()) {
254 logError(getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined")
256 logDebug(getProcessKey(execution) + ": Obtained BasicAuth credentials for VnfAdapter:" +
257 basicAuthValue, isDebugLogEnabled)
259 def encodedString = utils.getBasicAuth(basicAuthValue, execution.getVariable("URN_mso_msoKey"))
260 execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
261 } catch (IOException ex) {
262 logError(getProcessKey(execution) + ": Unable to encode BasicAuth credentials for VnfAdapter")
266 } catch (BpmnError e) {
267 logDebug(" Rethrowing MSOWorkflowException", isDebugLogEnabled)
269 } catch (Exception e) {
270 String msg = 'Caught exception in ' + method + ": " + e
272 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
277 * This method is used instead of an HTTP Connector task because the
278 * connector does not allow DELETE with a body.
280 public void sendRequestToVnfAdapter(Execution execution) {
281 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
282 'execution=' + execution.getId() +
284 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
285 logDebug('Entered ' + method, isDebugLogEnabled)
287 String prefix = execution.getVariable('prefix')
290 String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
291 String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
292 String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
294 RESTConfig config = new RESTConfig(vnfAdapterUrl)
295 RESTClient client = new RESTClient(config).
296 addHeader("Content-Type", "application/xml").
297 addAuthorizationHeader(execution.getVariable(prefix + "basicAuthHeaderValue"));
299 APIResponse response;
301 if ("GET".equals(vnfAdapterMethod)) {
302 response = client.httpGet()
303 } else if ("PUT".equals(vnfAdapterMethod)) {
304 response = client.httpPut(vnfAdapterRequest)
305 } else if ("POST".equals(vnfAdapterMethod)) {
306 response = client.httpPost(vnfAdapterRequest)
307 } else if ("DELETE".equals(vnfAdapterMethod)) {
308 response = client.httpDelete(vnfAdapterRequest)
310 String msg = 'Unsupported HTTP method "' + vnfAdapterMethod + '" in ' + method + ": " + e
312 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
315 execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatusCode())
316 execution.setVariable(prefix + "vnfAdapterResponse", response.getResponseBodyAsString())
317 } catch (BpmnError e) {
319 } catch (Exception e) {
320 String msg = 'Caught exception in ' + method + ": " + e
322 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
326 public void processCallback(Execution execution){
327 def method = getClass().getSimpleName() + '.processCallback(' +
328 'execution=' + execution.getId() +
330 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
331 logDebug('Entered ' + method, isDebugLogEnabled)
333 String callback = execution.getVariable('VNFAResponse_MESSAGE')
336 logDebug(getProcessKey(execution) + ": received callback:\n" + callback, isDebugLogEnabled)
338 // The XML callback is available to the calling flow in any case,
339 // even if a WorkflowException is generated.
340 execution.setVariable(getProcessKey(execution) + 'Response', callback)
341 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead.
342 execution.setVariable("WorkflowResponse", callback)
344 Node root = new XmlParser().parseText(callback)
345 if (root.name().endsWith('Exception')) {
346 vnfAdapterWorkflowException(execution, callback)
348 } catch (Exception e) {
350 callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
351 String msg = "Received error from VnfAdapter: " + callback
352 logDebug(getProcessKey(execution) + ': ' + msg, isDebugLogEnabled)
353 exceptionUtil.buildWorkflowException(execution, 7020, msg)
358 * Tries to parse the response as XML to extract the information to create
359 * a WorkflowException. If the response cannot be parsed, a more generic
360 * WorkflowException is created.
362 public void vnfAdapterWorkflowException(Execution execution, Object response) {
364 Node root = new XmlParser().parseText(response)
365 String category = getChildText(root, "category")
366 category = category == null || category.isEmpty() ? "" : " category='" + category + "'"
367 String message = getChildText(root, "message")
368 message = message == null || message.isEmpty() ? "" : " message='" + message + "'"
369 String rolledBack = getChildText(root, "rolledBack")
370 rolledBack = rolledBack == null || rolledBack.isEmpty() ? "" : " rolledBack='" + rolledBack + "'"
371 exceptionUtil.buildWorkflowException(execution, 7020, "Received " + root.name() +
372 " from VnfAdapter:" + category + message + rolledBack);
373 } catch (Exception e) {
374 response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
375 exceptionUtil.buildWorkflowException(execution, 7020, "Received error from VnfAdapter: " + response)
380 * Gets the named child of the specified node.
381 * @param node the node
382 * @param name the child name
383 * @return the child node, or null if no such child exists
385 private Node getChild(Node node, String name) {
386 for (Node child : node.children()) {
387 if (child.name() == name) {
395 * Gets the text of the named child of the specified node.
396 * @param node the node
397 * @param name the child name
398 * @return the child node text, or null if no such child exists
400 private String getChildText(Node node, String name) {
401 Node child = getChild(node, name)
402 return child == null ? null : child.text()