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.camunda.bpm.engine.delegate.BpmnError
24 import org.camunda.bpm.engine.runtime.Execution
25 import org.openecomp.mso.bpmn.core.WorkflowException
26 import org.openecomp.mso.rest.APIResponse
27 import org.springframework.web.util.UriUtils
30 public class UpdateAAIVfModule extends AbstractServiceTaskProcessor {
32 private XmlParser xmlParser = new XmlParser()
35 * Initialize the flow's variables.
37 * @param execution The flow's execution instance.
39 public void initProcessVariables(Execution execution) {
40 execution.setVariable('prefix', 'UAAIVfMod_')
41 execution.setVariable('UAAIVfMod_vnfId', null)
42 execution.setVariable('UAAIVfMod_vfModuleId', null)
43 execution.setVariable('UAAIVfMod_orchestrationStatus', null)
44 execution.setVariable('UAAIVfMod_heatStackId', null)
45 execution.setVariable('UAAIVfMod_volumeGroupId', null)
46 execution.setVariable('UAAIVfMod_getVfModuleResponseCode' ,null)
47 execution.setVariable('UAAIVfMod_getVfModuleResponse', '')
48 execution.setVariable('UAAIVfMod_updateVfModuleResponseCode', null)
49 execution.setVariable('UAAIVfMod_updateVfModuleResponse', '')
53 * Check for missing elements in the received request.
55 * @param execution The flow's execution instance.
57 public void preProcessRequest(Execution execution) {
58 def method = getClass().getSimpleName() + '.preProcessRequest(' +
59 'execution=' + execution.getId() +
61 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
62 logDebug('Entered ' + method, isDebugLogEnabled)
65 def xml = execution.getVariable('UpdateAAIVfModuleRequest')
66 logDebug('Received request xml:\n' + xml, isDebugLogEnabled)
67 utils.logAudit("UpdateAAIVfModule Request XML: " + xml)
68 initProcessVariables(execution)
70 def vnfId = getRequiredNodeText(execution, xml,'vnf-id')
71 execution.setVariable('UAAIVfMod_vnfId', vnfId)
73 def vfModuleId = getRequiredNodeText(execution, xml,'vf-module-id')
74 execution.setVariable('UAAIVfMod_vfModuleId', vfModuleId)
76 logDebug('Exited ' + method, isDebugLogEnabled)
77 } catch (BpmnError e) {
79 } catch (Exception e) {
80 logError('Caught exception in ' + method, e)
81 createWorkflowException(execution, 1002, 'Error in preProcessRequest(): ' + e.getMessage())
86 * Using the received vnfId and vfModuleId, query AAI to get the corresponding VF Module.
87 * A 200 response is expected with the VF Module in the response body.
89 * @param execution The flow's execution instance.
91 public void getVfModule(Execution execution) {
92 def method = getClass().getSimpleName() + '.getVfModule(' +
93 'execution=' + execution.getId() +
95 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
96 logDebug('Entered ' + method, isDebugLogEnabled)
99 def vnfId = execution.getVariable('UAAIVfMod_vnfId')
100 def vfModuleId = execution.getVariable('UAAIVfMod_vfModuleId')
102 // Construct endpoint
103 AaiUtil aaiUriUtil = new AaiUtil(this)
104 def aai_uri = aaiUriUtil.getNetworkGenericVnfUri(execution)
105 logDebug('AAI URI is: ' + aai_uri, isDebugLogEnabled)
106 String endPoint = execution.getVariable('URN_aai_endpoint') + aai_uri + '/' + UriUtils.encode(vnfId, "UTF-8") + '/vf-modules/vf-module/' + UriUtils.encode(vfModuleId, "UTF-8")
109 logDebug('sending GET to AAI endpoint \'' + endPoint + '\'', isDebugLogEnabled)
110 utils.logAudit("UpdateAAIVfModule sending GET to AAI endpoint: " + endPoint)
112 APIResponse response = aaiUriUtil.executeAAIGetCall(execution, endPoint)
113 def responseData = response.getResponseBodyAsString()
114 execution.setVariable('UAAIVfMod_getVfModuleResponseCode', response.getStatusCode())
115 execution.setVariable('UAAIVfMod_getVfModuleResponse', responseData)
116 logDebug('Response code:' + response.getStatusCode(), isDebugLogEnabled)
117 logDebug('Response:' + System.lineSeparator() + responseData, isDebugLogEnabled)
118 utils.logAudit("UpdateAAIVfModule response data: " + responseData)
119 } catch (Exception ex) {
121 logDebug('Exception occurred while executing AAI GET:' + ex.getMessage(),isDebugLogEnabled)
122 execution.setVariable('UAAIVfMod_getVfModuleResponseCode', 500)
123 execution.setVariable('UAAIVfMod_getVfModuleResponse', 'AAI GET Failed:' + ex.getMessage())
125 logDebug('Exited ' + method, isDebugLogEnabled)
126 } catch (BpmnError e) {
128 } catch (Exception e) {
129 logError('Caught exception in ' + method, e)
130 createWorkflowException(execution, 1002, 'Error in getVfModule(): ' + e.getMessage())
135 * Construct and send a PUT request to AAI to update the VF Module.
137 * @param execution The flow's execution instance.
139 public void updateVfModule(Execution execution) {
140 def method = getClass().getSimpleName() + '.updateVfModule(' +
141 'execution=' + execution.getId() +
143 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
144 logDebug('Entered ' + method, isDebugLogEnabled)
147 def vnfId = execution.getVariable('UAAIVfMod_vnfId')
148 def vfModuleId = execution.getVariable('UAAIVfMod_vfModuleId')
149 def vfModule = execution.getVariable('UAAIVfMod_getVfModuleResponse')
150 def origRequest = execution.getVariable('UpdateAAIVfModuleRequest')
151 def Node vfModuleNode = xmlParser.parseText(vfModule)
153 utils.logAudit("UpdateAAIVfModule request: " + origRequest)
154 // Confirm resource-version is in retrieved VF Module
155 if (utils.getChildNode(vfModuleNode, 'resource-version') == null) {
156 def msg = 'Can\'t update VF Module ' + vfModuleId + ' since \'resource-version\' is missing'
158 throw new Exception(msg)
161 // TEMPORARY!!! Disable Volume Group Check
162 // Check volume-group-id conditions
163 //def checkVgiResult = checkVolumeGroupId(origRequest, vfModuleNode, isDebugLogEnabled)
164 //if (checkVgiResult != null) {
165 // def msg = 'Can\'t update VF Module ' + vfModuleId + ': ' + checkVgiResult
167 // throw new Exception(msg)
170 // Handle persona-model-id/persona-model-version
171 def boolean doPersonaModelVersion = true
172 def String newPersonaModelId = utils.getNodeText1(origRequest, 'persona-model-id')
173 def String newPersonaModelVersion = utils.getNodeText1(origRequest, 'persona-model-version')
174 if ((newPersonaModelId == null) || (newPersonaModelVersion == null)) {
175 doPersonaModelVersion = false
177 // Confirm "new" persona-model-id is same as "current" persona-model-id
178 def String currPersonaModelId = utils.getChildNodeText(vfModuleNode, 'persona-model-id')
179 if (currPersonaModelId == null) {
180 currPersonaModelId = ''
182 if (!newPersonaModelId.equals(currPersonaModelId)) {
183 def msg = 'Can\'t update VF Module ' + vfModuleId + ' since there is \'persona-model-id\' mismatch between the current and new values'
185 throw new Exception(msg)
190 updateVfModuleNode(origRequest, vfModuleNode, 'orchestration-status')
191 updateVfModuleNode(origRequest, vfModuleNode, 'heat-stack-id')
192 if (doPersonaModelVersion) {
193 updateVfModuleNode(origRequest, vfModuleNode, 'persona-model-version')
195 updateVfModuleNode(origRequest, vfModuleNode, 'contrail-service-instance-fqdn')
196 def payload = utils.nodeToString(vfModuleNode)
198 // Construct endpoint
199 AaiUtil aaiUriUtil = new AaiUtil(this)
200 def aai_uri = aaiUriUtil.getNetworkGenericVnfUri(execution)
201 logDebug('AAI URI is: ' + aai_uri, isDebugLogEnabled)
202 String endPoint = execution.getVariable('URN_aai_endpoint') + aai_uri + '/' + UriUtils.encode(vnfId, "UTF-8") + '/vf-modules/vf-module/' + UriUtils.encode(vfModuleId, "UTF-8")
205 logDebug('sending PUT to AAI endpoint \'' + endPoint + '\'' + 'with payload \n' + payload, isDebugLogEnabled)
206 utils.logAudit("Sending PUT to AAI endpoint: " + endPoint)
208 APIResponse response = aaiUriUtil.executeAAIPutCall(execution, endPoint, payload)
209 def responseData = response.getResponseBodyAsString()
210 execution.setVariable('UAAIVfMod_updateVfModuleResponseCode', response.getStatusCode())
211 execution.setVariable('UAAIVfMod_updateVfModuleResponse', responseData)
212 utils.logAudit("UpdateAAIVfModule Response data: " + responseData)
213 logDebug('Response code:' + response.getStatusCode(), isDebugLogEnabled)
214 logDebug('Response:' + System.lineSeparator() + responseData, isDebugLogEnabled)
215 } catch (Exception ex) {
217 logDebug('Exception occurred while executing AAI PUT:' + ex.getMessage(),isDebugLogEnabled)
218 execution.setVariable('UAAIVfMod_updateVfModuleResponseCode', 500)
219 execution.setVariable('UAAIVfMod_updateVfModuleResponse', 'AAI PUT Failed:' + ex.getMessage())
221 logDebug('Exited ' + method, isDebugLogEnabled)
222 } catch (BpmnError e) {
224 } catch (Exception e) {
225 logError('Caught exception in ' + method, e)
226 createWorkflowException(execution, 1002, 'Error in updateVfModule(): ' + e.getMessage())
231 * Insert a new Node, replace the value of an existing Node, or delete an existing Node in the current
232 * VF Module Node, as necessary.
234 * If the Node with the same name already exists in current VF Module, but is not being updated, then do
235 * nothing. If the element is being updated and it already exists in the current VF Module, then check
236 * the value specified in the original request. If the value is 'DELETE', remove that Node from the
237 * current VF Module. Otherwise, change the value to the specified new value. If the element is
238 * being updated but doesn't exist in the current VF Module, and the new value is not 'DELETE', then
239 * create an appropriate new node and add it to the VF Module.
241 * @param origRequest Incoming update request with VF Module elements to be updated.
242 * @param vfModule Current VF Module retrieved from AAI.
243 * @param element Name of element to be inserted.
245 private void updateVfModuleNode(String origRequest, Node vfModuleNode, String elementName) {
247 if (!utils.nodeExists(origRequest, elementName)) {
250 def elementValue = utils.getNodeText(origRequest, elementName)
252 def Node childNode = utils.getChildNode(vfModuleNode, elementName)
253 if (childNode == null) {
254 if (elementValue.equals('DELETE')) {
255 // Element doesn't exist but is being deleted, so do nothing
258 // Node doesn't exist, create a new Node as a child
259 new Node(vfModuleNode, elementName, elementValue)
261 if (elementValue.equals('DELETE')) {
262 // Node exists, but should be deleted
263 vfModuleNode.remove(childNode)
265 // Node already exists, just give it a new value
266 childNode.setValue(elementValue)
272 * Check the Volume Group ID from the incoming update request against the Volume Group ID from the
273 * given VF Module. If they are equal or if they are both 'null', then that is acceptable and 'null'
274 * is returned. Otherwise a message describing how the values are unacceptable/incompatible is returned.
276 * @param origRequest Incoming update request with VF Module elements to be updated.
277 * @param vfModuleNode VF Module (as a Node) retrieved from AAI.
278 * @param isDebugLogEnabled Is DEBUG log enabled?
279 * @return 'null' if the Volume Group IDs are acceptable. Otherwise return a message describing how the
280 * values are unacceptable/incompatible.
282 private String checkVolumeGroupId(String origRequest, Node vfModuleNode, String isDebugLogEnabled) {
283 def requestVolumeGroupId = utils.getNodeText1(origRequest, 'volume-group-id')
284 def currVolumeGroupId = getCurrVolumeGroupId(vfModuleNode)
286 logDebug('Check volume-group-id: volume-group-id in original request is \'' + requestVolumeGroupId +
287 '\', volume-group-id from VF Module is \'' + currVolumeGroupId + '\'', isDebugLogEnabled)
291 if (requestVolumeGroupId == null) {
292 if (currVolumeGroupId == null) {
295 result = 'Cannot detach a volume group from an existing VF Module'
298 if (currVolumeGroupId == null) {
299 result = 'Cannot add a volume gruop to an existing VF Module'
301 if (!requestVolumeGroupId.equals(currVolumeGroupId)) {
302 result = 'Cannot change the volume group on an existing VF Module'
311 * Find and return the value of the Volume Group ID for the specified VF Module. If
312 * the value of the Volume Group ID cannot be found for any reason, 'null' is returned.
314 * @param vfModuleNode VF Module (as a Node) retrieved from AAI.
315 * @return the value of the Volume Group ID for the specified VF Module. If the
316 * value of the Volume Group ID cannot be found for any reason, 'null' is returned.
318 private String getCurrVolumeGroupId(Node vfModuleNode) {
319 def Node relationshipList = utils.getChildNode(vfModuleNode, 'relationship-list')
320 if (relationshipList == null) {
323 def NodeList relationships = utils.getIdenticalChildren(relationshipList, 'relationship')
324 for (Node relationshipNode in relationships) {
325 def String relatedTo = utils.getChildNodeText(relationshipNode, 'related-to')
326 if ((relatedTo != null) && relatedTo.equals('volume-group')) {
327 def NodeList relationshipDataList = utils.getIdenticalChildren(relationshipNode, 'relationship-data')
328 for (Node relationshipDataNode in relationshipDataList) {
329 def String relationshipKey = utils.getChildNodeText(relationshipDataNode, 'relationship-key')
330 if ((relationshipKey != null) && relationshipKey.equals('volume-group.volume-group-id')) {
331 return utils.getChildNodeText(relationshipDataNode, 'relationship-value')
340 * Generates a WorkflowException if the AAI query returns a response code other than 200.
342 * @param execution The flow's execution instance.
344 public void handleAAIQueryFailure(Execution execution) {
345 def method = getClass().getSimpleName() + '.handleAAIQueryFailure(' +
346 'execution=' + execution.getId() +
348 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
349 logDebug('Entered ' + method, isDebugLogEnabled)
351 logError('Error occurred attempting to query AAI, Response Code ' +
352 execution.getVariable('UAAIVfMod_getVfModuleResponseCode') + ', Error Response ' +
353 execution.getVariable('UAAIVfMod_getVfModuleResponse'))
354 String processKey = getProcessKey(execution);
355 WorkflowException exception = new WorkflowException(processKey, 5000,
356 execution.getVariable('UAAIVfMod_getVfModuleResponse'))
357 execution.setVariable('WorkflowException', exception)
358 utils.logAudit("UpdateAAIVfModule query failure: " + exception.getErrorMessage())
359 logDebug('Exited ' + method, isDebugLogEnabled)
363 * Generates a WorkflowException if updating a VF Module in AAI returns a response code other than 200.
365 * @param execution The flow's execution instance.
367 public void handleUpdateVfModuleFailure(Execution execution) {
368 def method = getClass().getSimpleName() + '.handleUpdateVfModuleFailure(' +
369 'execution=' + execution.getId() +
371 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
372 logDebug('Entered ' + method, isDebugLogEnabled)
374 logError('Error occurred attempting to update VF Module in AAI, Response Code ' +
375 execution.getVariable('UAAIVfMod_updateVfModuleResponseCode') + ', Error Response ' +
376 execution.getVariable('UAAIVfMod_updateVfModuleResponse'))
377 String processKey = getProcessKey(execution);
378 WorkflowException exception = new WorkflowException(processKey, 5000,
379 execution.getVariable('UAAIVfMod_updateVfModuleResponse'))
380 execution.setVariable('WorkflowException', exception)
382 utils.logAudit("UpdateAAIVfModule failure: " + exception.getErrorMessage())
383 logDebug('Exited ' + method, isDebugLogEnabled)