2 * ============LICENSE_START=======================================================
\r
4 * ================================================================================
\r
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * ================================================================================
\r
7 * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * you may not use this file except in compliance with the License.
\r
9 * You may obtain a copy of the License at
\r
11 * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * Unless required by applicable law or agreed to in writing, software
\r
14 * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * See the License for the specific language governing permissions and
\r
17 * limitations under the License.
\r
18 * ============LICENSE_END=========================================================
\r
21 package org.openecomp.mso.bpmn.common.scripts
\r
23 import org.apache.commons.lang3.*
\r
24 import org.camunda.bpm.engine.delegate.BpmnError
\r
25 import org.camunda.bpm.engine.delegate.DelegateExecution
\r
26 import org.openecomp.mso.rest.APIResponse
\r
27 import org.openecomp.mso.rest.RESTClient
\r
28 import org.openecomp.mso.rest.RESTConfig
\r
30 class VnfAdapterRestV1 extends AbstractServiceTaskProcessor {
\r
32 ExceptionUtil exceptionUtil = new ExceptionUtil()
\r
34 // VNF Response Processing
\r
35 public void preProcessRequest (DelegateExecution execution) {
\r
36 def method = getClass().getSimpleName() + '.preProcessRequest(' +
\r
37 'execution=' + execution.getId() +
\r
39 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
\r
40 logDebug('Entered ' + method, isDebugLogEnabled)
\r
42 def prefix="VNFREST_"
\r
43 execution.setVariable("prefix", prefix)
\r
44 setSuccessIndicator(execution, false)
\r
47 String request = validateRequest(execution, "mso-request-id")
\r
49 // Get the request type (the name of the root element) from the request
\r
51 Node root = new XmlParser().parseText(request)
\r
52 String requestType = root.name()
\r
53 execution.setVariable(prefix + 'requestType', requestType)
\r
54 logDebug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType, isDebugLogEnabled)
\r
56 utils.logAudit('VnfAdapterRestV1, request: ' + request)
\r
57 // Get the messageId from the request
\r
59 String messageId = getChildText(root, 'messageId')
\r
61 if ('rollbackVolumeGroupRequest'.equals(requestType)) {
\r
62 messageId = getMessageIdForVolumeGroupRollback(root)
\r
65 if (messageId == null || messageId.isEmpty()) {
\r
66 String msg = getProcessKey(execution) + ': no messageId in ' + requestType
\r
68 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
71 execution.setVariable('VNFAResponse_CORRELATOR', messageId)
\r
72 logDebug(getProcessKey(execution) + ': VNFAResponse_CORRELATOR = ' + messageId, isDebugLogEnabled)
\r
74 // Get the notificationUrl from the request
\r
76 String notificationUrl = getChildText(root, 'notificationUrl')
\r
78 if (notificationUrl == null || notificationUrl.isEmpty()) {
\r
79 String msg = getProcessKey(execution) + ': no notificationUrl in ' + requestType
\r
81 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
84 execution.setVariable(prefix + 'notificationUrl', notificationUrl)
\r
85 logDebug(getProcessKey(execution) + ': ' + prefix + 'notificationUrl = ' + notificationUrl, isDebugLogEnabled)
\r
87 // Determine the VnfAdapter endpoint
\r
89 String vnfAdapterEndpoint = execution.getVariable("URN_mso_adapters_vnf_rest_endpoint")
\r
91 if (vnfAdapterEndpoint == null || vnfAdapterEndpoint.isEmpty()) {
\r
92 String msg = getProcessKey(execution) + ': mso:adapters:vnf:rest:endpoint URN mapping is not defined'
\r
94 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
97 while (vnfAdapterEndpoint.endsWith('/')) {
\r
98 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, vnfAdapterEndpoint.length()-1)
\r
101 String vnfAdapterMethod = null
\r
102 String vnfAdapterUrl = null
\r
103 String vnfAdapterRequest = request
\r
105 if ('createVfModuleRequest'.equals(requestType)) {
\r
106 String vnfId = getChildText(root, 'vnfId')
\r
108 if (vnfId == null || vnfId.isEmpty()) {
\r
109 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
\r
111 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
114 vnfAdapterMethod = 'POST'
\r
115 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') + '/vf-modules'
\r
117 } else if ('updateVfModuleRequest'.equals(requestType)) {
\r
118 String vnfId = getChildText(root, 'vnfId')
\r
120 if (vnfId == null || vnfId.isEmpty()) {
\r
121 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
\r
123 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
126 String vfModuleId = getChildText(root, 'vfModuleId')
\r
128 if (vfModuleId == null || vfModuleId.isEmpty()) {
\r
129 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
\r
131 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
134 vnfAdapterMethod = 'PUT'
\r
135 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
\r
136 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
\r
138 } else if ('deleteVfModuleRequest'.equals(requestType)) {
\r
139 String vnfId = getChildText(root, 'vnfId')
\r
141 if (vnfId == null || vnfId.isEmpty()) {
\r
142 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
\r
144 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
147 String vfModuleId = getChildText(root, 'vfModuleId')
\r
149 if (vfModuleId == null || vfModuleId.isEmpty()) {
\r
150 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
\r
152 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
155 vnfAdapterMethod = 'DELETE'
\r
156 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
\r
157 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8')
\r
159 } else if ('rollbackVfModuleRequest'.equals(requestType)) {
\r
160 Node vfModuleRollbackNode = getChild(root, 'vfModuleRollback')
\r
162 if (vfModuleRollbackNode == null) {
\r
163 String msg = getProcessKey(execution) + ': no vfModuleRollback in ' + requestType
\r
165 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
168 String vnfId = getChildText(vfModuleRollbackNode, 'vnfId')
\r
170 if (vnfId == null || vnfId.isEmpty()) {
\r
171 String msg = getProcessKey(execution) + ': no vnfId in ' + requestType
\r
173 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
176 String vfModuleId = getChildText(vfModuleRollbackNode, 'vfModuleId')
\r
178 if (vfModuleId == null || vfModuleId.isEmpty()) {
\r
179 String msg = getProcessKey(execution) + ': no vfModuleId in ' + requestType
\r
181 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
184 vnfAdapterMethod = 'DELETE'
\r
185 vnfAdapterUrl = vnfAdapterEndpoint + '/' + URLEncoder.encode(vnfId, 'UTF-8') +
\r
186 '/vf-modules/' + URLEncoder.encode(vfModuleId, 'UTF-8') + '/rollback'
\r
188 } else if ('createVolumeGroupRequest'.equals(requestType)) {
\r
189 vnfAdapterMethod = 'POST'
\r
190 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
\r
191 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
\r
193 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups'
\r
195 } else if ('updateVolumeGroupRequest'.equals(requestType)) {
\r
196 String volumeGroupId = getChildText(root, 'volumeGroupId')
\r
198 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
\r
199 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
\r
201 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
204 vnfAdapterMethod = 'PUT'
\r
205 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
\r
206 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
\r
208 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
\r
210 } else if ('deleteVolumeGroupRequest'.equals(requestType)) {
\r
211 String volumeGroupId = getChildText(root, 'volumeGroupId')
\r
213 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
\r
214 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
\r
216 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
219 vnfAdapterMethod = 'DELETE'
\r
220 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
\r
221 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
\r
223 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8')
\r
225 } else if ('rollbackVolumeGroupRequest'.equals(requestType)) {
\r
226 String volumeGroupId = root.'volumeGroupRollback'.'volumeGroupId'.text()
\r
228 if (volumeGroupId == null || volumeGroupId.isEmpty()) {
\r
229 String msg = getProcessKey(execution) + ': no volumeGroupId in ' + requestType
\r
231 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
234 vnfAdapterMethod = 'DELETE'
\r
235 if (vnfAdapterEndpoint.endsWith('v1/vnfs')) {
\r
236 vnfAdapterEndpoint = vnfAdapterEndpoint.substring(0, (vnfAdapterEndpoint.length()-'/vnfs'.length()))
\r
238 vnfAdapterUrl = vnfAdapterEndpoint + '/volume-groups/' + URLEncoder.encode(volumeGroupId, 'UTF-8') + '/rollback'
\r
241 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
\r
243 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
246 execution.setVariable(prefix + 'vnfAdapterMethod', vnfAdapterMethod)
\r
247 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterMethod = ' + vnfAdapterMethod, isDebugLogEnabled)
\r
248 execution.setVariable(prefix + 'vnfAdapterUrl', vnfAdapterUrl)
\r
249 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterUrl = ' + vnfAdapterUrl, isDebugLogEnabled)
\r
250 execution.setVariable(prefix + 'vnfAdapterRequest', vnfAdapterRequest)
\r
251 logDebug(getProcessKey(execution) + ': ' + prefix + 'vnfAdapterRequest = \n' + vnfAdapterRequest, isDebugLogEnabled)
\r
253 // Get the Basic Auth credentials for the VnfAdapter
\r
255 String basicAuthValue = execution.getVariable("URN_mso_adapters_po_auth")
\r
257 if (basicAuthValue == null || basicAuthValue.isEmpty()) {
\r
258 logError(getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined")
\r
260 logDebug(getProcessKey(execution) + ": Obtained BasicAuth credentials for VnfAdapter:" +
\r
261 basicAuthValue, isDebugLogEnabled)
\r
263 def encodedString = utils.getBasicAuth(basicAuthValue, execution.getVariable("URN_mso_msoKey"))
\r
264 execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
\r
265 } catch (IOException ex) {
\r
266 logError(getProcessKey(execution) + ": Unable to encode BasicAuth credentials for VnfAdapter")
\r
270 } catch (BpmnError e) {
\r
271 logDebug(" Rethrowing MSOWorkflowException", isDebugLogEnabled)
\r
273 } catch (Exception e) {
\r
274 String msg = 'Caught exception in ' + method + ": " + e
\r
277 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
281 public String getMessageIdForVolumeGroupRollback(Node root) {
\r
282 return root.'volumeGroupRollback'.'messageId'.text()
\r
286 * This method is used instead of an HTTP Connector task because the
\r
287 * connector does not allow DELETE with a body.
\r
289 public void sendRequestToVnfAdapter(DelegateExecution execution) {
\r
290 def method = getClass().getSimpleName() + '.sendRequestToVnfAdapter(' +
\r
291 'execution=' + execution.getId() +
\r
293 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
\r
294 logDebug('Entered ' + method, isDebugLogEnabled)
\r
296 String prefix = execution.getVariable('prefix')
\r
299 String vnfAdapterMethod = execution.getVariable(prefix + 'vnfAdapterMethod')
\r
300 String vnfAdapterUrl = execution.getVariable(prefix + 'vnfAdapterUrl')
\r
301 String vnfAdapterRequest = execution.getVariable(prefix + 'vnfAdapterRequest')
\r
303 RESTConfig config = new RESTConfig(vnfAdapterUrl)
\r
304 RESTClient client = new RESTClient(config).
\r
305 addHeader("Content-Type", "application/xml").
\r
306 addAuthorizationHeader(execution.getVariable(prefix + "basicAuthHeaderValue"));
\r
308 APIResponse response;
\r
310 if ("GET".equals(vnfAdapterMethod)) {
\r
311 response = client.httpGet()
\r
312 } else if ("PUT".equals(vnfAdapterMethod)) {
\r
313 response = client.httpPut(vnfAdapterRequest)
\r
314 } else if ("POST".equals(vnfAdapterMethod)) {
\r
315 response = client.httpPost(vnfAdapterRequest)
\r
316 } else if ("DELETE".equals(vnfAdapterMethod)) {
\r
317 response = client.httpDelete(vnfAdapterRequest)
\r
319 String msg = 'Unsupported HTTP method "' + vnfAdapterMethod + '" in ' + method + ": " + e
\r
321 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
324 execution.setVariable(prefix + "vnfAdapterStatusCode", response.getStatusCode())
\r
325 execution.setVariable(prefix + "vnfAdapterResponse", response.getResponseBodyAsString())
\r
326 } catch (BpmnError e) {
\r
328 } catch (Exception e) {
\r
329 String msg = 'Caught exception in ' + method + ": " + e
\r
331 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
\r
335 public void processCallback(DelegateExecution execution){
\r
336 def method = getClass().getSimpleName() + '.processCallback(' +
\r
337 'execution=' + execution.getId() +
\r
339 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
\r
340 logDebug('Entered ' + method, isDebugLogEnabled)
\r
342 String callback = execution.getVariable('VNFAResponse_MESSAGE')
\r
345 logDebug(getProcessKey(execution) + ": received callback:\n" + callback, isDebugLogEnabled)
\r
347 // The XML callback is available to the calling flow in any case,
\r
348 // even if a WorkflowException is generated.
\r
349 execution.setVariable(getProcessKey(execution) + 'Response', callback)
\r
350 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead.
\r
351 execution.setVariable("WorkflowResponse", callback)
\r
353 Node root = new XmlParser().parseText(callback)
\r
354 if (root.name().endsWith('Exception')) {
\r
355 vnfAdapterWorkflowException(execution, callback)
\r
357 } catch (Exception e) {
\r
358 e.printStackTrace()
\r
359 callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
\r
360 String msg = "Received error from VnfAdapter: " + callback
\r
361 logDebug(getProcessKey(execution) + ': ' + msg, isDebugLogEnabled)
\r
362 exceptionUtil.buildWorkflowException(execution, 7020, msg)
\r
367 * Tries to parse the response as XML to extract the information to create
\r
368 * a WorkflowException. If the response cannot be parsed, a more generic
\r
369 * WorkflowException is created.
\r
371 public void vnfAdapterWorkflowException(DelegateExecution execution, Object response) {
\r
373 Node root = new XmlParser().parseText(response)
\r
374 String category = getChildText(root, "category")
\r
375 category = category == null || category.isEmpty() ? "" : " category='" + category + "'"
\r
376 String message = getChildText(root, "message")
\r
377 message = message == null || message.isEmpty() ? "" : " message='" + message + "'"
\r
378 String rolledBack = getChildText(root, "rolledBack")
\r
379 rolledBack = rolledBack == null || rolledBack.isEmpty() ? "" : " rolledBack='" + rolledBack + "'"
\r
380 exceptionUtil.buildWorkflowException(execution, 7020, "Received " + root.name() +
\r
381 " from VnfAdapter:" + category + message + rolledBack);
\r
382 } catch (Exception e) {
\r
383 response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
\r
384 exceptionUtil.buildWorkflowException(execution, 7020, "Received error from VnfAdapter: " + response)
\r
389 * Gets the named child of the specified node.
\r
390 * @param node the node
\r
391 * @param name the child name
\r
392 * @return the child node, or null if no such child exists
\r
394 private Node getChild(Node node, String name) {
\r
395 for (Node child : node.children()) {
\r
396 if (child.name() == name) {
\r
404 * Gets the text of the named child of the specified node.
\r
405 * @param node the node
\r
406 * @param name the child name
\r
407 * @return the child node text, or null if no such child exists
\r
409 private String getChildText(Node node, String name) {
\r
410 Node child = getChild(node, name)
\r
411 return child == null ? null : child.text()
\r