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.infrastructure.scripts
25 import org.onap.so.logger.LoggingAnchor
26 import groovy.json.JsonException
27 import groovy.json.JsonSlurper
28 import org.camunda.bpm.engine.delegate.BpmnError
29 import org.camunda.bpm.engine.delegate.DelegateExecution
30 import org.onap.aai.domain.yang.GenericVnf
31 import org.onap.aai.domain.yang.VfModule
32 import org.onap.aai.domain.yang.VolumeGroup
33 import org.onap.so.bpmn.common.scripts.ExceptionUtil
34 import org.onap.so.bpmn.common.scripts.MsoUtils
35 import org.onap.so.bpmn.common.scripts.VfModuleBase
36 import org.onap.so.bpmn.common.scripts.VidUtils
37 import org.onap.so.bpmn.core.UrnPropertiesReader
38 import org.onap.so.bpmn.core.WorkflowException
39 import org.onap.so.client.aai.AAIObjectType
40 import org.onap.so.client.aai.entities.AAIResultWrapper
41 import org.onap.so.client.aai.entities.Relationships
42 import org.onap.so.client.aai.entities.uri.AAIResourceUri
43 import org.onap.so.client.aai.entities.uri.AAIUriFactory
44 import org.onap.so.constants.Defaults
45 import org.onap.logging.filter.base.ErrorCode
46 import org.onap.so.logger.MessageEnum
47 import org.slf4j.Logger
48 import org.slf4j.LoggerFactory
50 import javax.ws.rs.core.UriBuilder
52 import static org.apache.cxf.common.util.CollectionUtils.isEmpty
54 class UpdateVfModuleVolumeInfraV1 extends VfModuleBase {
55 private static final Logger logger = LoggerFactory.getLogger(UpdateVfModuleVolumeInfraV1.class)
56 private ExceptionUtil exceptionUtil = new ExceptionUtil()
59 * Initialize the flow's variables.
61 * @param execution The flow's execution instance.
63 private void initProcessVariables(DelegateExecution execution) {
64 execution.setVariable('prefix', 'UPDVfModVol_')
65 execution.setVariable('UPDVfModVol_Request', null)
66 execution.setVariable('UPDVfModVol_requestInfo', null)
67 execution.setVariable('UPDVfModVol_requestId', null)
68 execution.setVariable('UPDVfModVol_source', null)
69 execution.setVariable('UPDVfModVol_volumeInputs', null)
70 execution.setVariable('UPDVfModVol_volumeGroupId', null)
71 execution.setVariable('UPDVfModVol_vnfType', null)
72 execution.setVariable('UPDVfModVol_serviceId', null)
73 execution.setVariable('UPDVfModVol_aicCloudRegion', null)
74 execution.setVariable('UPDVfModVol_tenantId', null)
75 execution.setVariable('UPDVfModVol_volumeParams', null)
76 execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', null)
77 execution.setVariable('UPDVfModVol_volumeGroupTenantId', null)
78 execution.setVariable('UpdateVfModuleVolumeSuccessIndicator', false)
82 * Perform initial processing, such as request validation, initialization of variables, etc.
85 public void preProcessRequest(DelegateExecution execution) {
86 def isDebugEnabled = execution.getVariable("isDebugLogEnabled")
87 preProcessRequest(execution, isDebugEnabled)
90 public void preProcessRequest(DelegateExecution execution, isDebugLogEnabled) {
92 initProcessVariables(execution)
93 String jsonRequest = validateRequest(execution)
98 def jsonSlurper = new JsonSlurper()
99 Map reqMap = jsonSlurper.parseText(jsonRequest)
101 def serviceInstanceId = execution.getVariable('serviceInstanceId')
102 def volumeGroupId = execution.getVariable('volumeGroupId')
103 //def vnfId = execution.getVariable('vnfId')
105 def vidUtils = new VidUtils(this)
106 request = vidUtils.createXmlVolumeRequest(reqMap, 'UPDATE_VF_MODULE_VOL', serviceInstanceId, volumeGroupId)
108 execution.setVariable('UPDVfModVol_Request', request)
109 execution.setVariable("UPDVfModVol_isVidRequest", true)
111 //need to get persona-model-id aka model-invariantId to use later to validate vf-module relation in AAI
113 def modelInvariantId = reqMap.requestDetails.modelInfo.modelInvariantUuid ?: ''
114 execution.setVariable('UPDVfModVol_modelInvariantId', modelInvariantId)
116 logger.debug("modelInvariantId from request: {}", modelInvariantId)
117 logger.debug("XML request:\n{}", request)
119 catch (JsonException je) {
120 logger.debug(" Request is in XML format.")
121 // assume request is in XML format - proceed as usual to process XML request
124 def requestId = execution.getVariable('mso-request-id')
126 def requestInfo = getRequiredNodeXml(execution, request, 'request-info')
127 execution.setVariable('UPDVfModVol_requestInfo', requestInfo)
128 execution.setVariable('UPDVfModVol_requestId', requestId)
129 //execution.setVariable('UPDVfModVol_requestId', getRequiredNodeText(execution, requestInfo, 'request-id'))
130 execution.setVariable('UPDVfModVol_source', getNodeTextForce(requestInfo, 'source'))
132 def volumeInputs = getRequiredNodeXml(execution, request, 'volume-inputs')
133 execution.setVariable('UPDVfModVol_volumeInputs', volumeInputs)
134 execution.setVariable('UPDVfModVol_volumeGroupId', getRequiredNodeText(execution, volumeInputs, 'volume-group-id'))
135 execution.setVariable('UPDVfModVol_vnfType', getRequiredNodeText(execution, volumeInputs, 'vnf-type'))
136 execution.setVariable('UPDVfModVol_vnfVersion', getRequiredNodeText(execution, volumeInputs, 'asdc-service-model-version'))
137 execution.setVariable('UPDVfModVol_serviceId', utils.getNodeText(volumeInputs, 'service-id'))
138 execution.setVariable('UPDVfModVol_aicCloudRegion', getRequiredNodeText(execution, volumeInputs, 'aic-cloud-region'))
139 execution.setVariable('UPDVfModVol_cloudRegion', getRequiredNodeText(execution, volumeInputs, 'cloud-owner'))
140 execution.setVariable('UPDVfModVol_tenantId', getRequiredNodeText(execution, volumeInputs, 'tenant-id'))
141 //execution.setVariable('UPDVfModVol_modelCustomizationId', getRequiredNodeText(execution, volumeInputs, 'model-customization-id'))
143 setBasicDBAuthHeader(execution, isDebugLogEnabled)
145 def volumeParams = utils.getNodeXml(request, 'volume-params')
146 execution.setVariable('UPDVfModVol_volumeParams', volumeParams)
150 * Prepare and send the synchronous response.
152 * @param execution The flow's execution instance.
154 public void sendSynchResponse(DelegateExecution execution, isDebugLogEnabled) {
156 def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
157 def requestId = execution.getVariable('UPDVfModVol_requestId')
158 def source = execution.getVariable('UPDVfModVol_source')
159 def progress = getNodeTextForce(requestInfo, 'progress')
160 if (progress.isEmpty()) {
163 def startTime = getNodeTextForce(requestInfo, 'start-time')
164 if (startTime.isEmpty()) {
165 startTime = System.currentTimeMillis()
167 def volumeInputs = execution.getVariable('UPDVfModVol_volumeInputs')
169 String xmlSyncResponse = """
170 <volume-request xmlns="http://org.onap/so/infra/vnf-request/v1">
172 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
173 <action>UPDATE_VF_MODULE_VOL</action>
174 <request-status>IN_PROGRESS</request-status>
175 <progress>${MsoUtils.xmlEscape(progress)}</progress>
176 <start-time>${MsoUtils.xmlEscape(startTime)}</start-time>
177 <source>${MsoUtils.xmlEscape(source)}</source>
183 def syncResponse = ''
184 def isVidRequest = execution.getVariable('UPDVfModVol_isVidRequest')
187 def volumeGroupId = execution.getVariable('volumeGroupId')
188 syncResponse = """{"requestReferences":{"instanceId":"${volumeGroupId}","requestId":"${
192 syncResponse = utils.formatXml(xmlSyncResponse)
195 logger.debug('Sync response: {}', syncResponse)
196 execution.setVariable('UPDVfModVol_syncResponseSent', true)
197 sendWorkflowResponse(execution, 200, syncResponse)
201 * Prepare a Request for querying AAI for Volume Group information using the
202 * Volume Group Id and Aic Cloud Region.
203 * @param execution The flow's execution instance.
205 public void queryAAIForVolumeGroup(DelegateExecution execution, isDebugLogEnabled) {
207 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
208 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
211 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(), aicCloudRegion, volumeGroupId)
212 AAIResultWrapper wrapper = getAAIClient().get(uri)
213 Optional<VolumeGroup> volumeGroup = wrapper.asBean(VolumeGroup.class)
214 if (volumeGroup.isPresent()) {
215 execution.setVariable('UPDVfModVol_aaiVolumeGroupResponse', volumeGroup.get())
216 Optional<Relationships> relationships = wrapper.getRelationships()
217 if (relationships.isPresent()) {
218 List<AAIResourceUri> tenantURIList = relationships.get().getRelatedAAIUris(AAIObjectType.TENANT)
219 if (!isEmpty(tenantURIList)) {
220 String volumeGroupTenantId = tenantURIList.get(0).getURIKeys().get("tenant-id")
221 execution.setVariable('UPDVfModVol_volumeGroupTenantId', volumeGroupTenantId)
222 logger.debug("Received Tenant Id {} from AAI for Volume Group with Volume Group Id {}, AIC Cloud Region ",
223 volumeGroupTenantId, volumeGroupId, aicCloudRegion)
225 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id " + volumeGroupId
226 + ", AIC Cloud Region " + aicCloudRegion)
228 execution.setVariable('UPDVfModVol_relatedVfModuleLink', relationships.get().getRelatedLinks(AAIObjectType.VF_MODULE).get(0))
231 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id " + volumeGroupId
232 + ", AIC Cloud Region " + aicCloudRegion)
235 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group " + volumeGroupId + " not found at AAI")
237 }catch(BpmnError bpmnError){
240 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - Occured During queryAAIForGenericVnf"+e.getMessage())
245 * Query AAI service instance
247 * @param isDebugEnabled
249 public void queryAAIForGenericVnf(DelegateExecution execution, isDebugEnabled) {
251 def vnfId = execution.getVariable('vnfId')
253 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId)
255 Optional<GenericVnf> genericVnf = getAAIClient().get(GenericVnf.class, uri)
256 if (genericVnf.isPresent()) {
257 execution.setVariable('UPDVfModVol_AAIQueryGenericVfnResponse', genericVnf.get())
259 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, 'Generic vnf ' + vnfId + ' was not found in AAI. Return code: 404.')
261 }catch(BpmnError bpmnError){
264 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - Occured During queryAAIForGenericVnf"+e.getMessage())
269 * Query AAI for VF Module using vf-module-id
271 * @param isDebugLogEnabled
273 public void queryAAIForVfModule(DelegateExecution execution, isDebugLogEnabled) {
275 String queryAAIVfModuleRequest = execution.getVariable('UPDVfModVol_relatedVfModuleLink')
276 execution.setVariable('UPDVfModVol_personaModelId', '')
277 AAIResourceUri uri = AAIUriFactory.createResourceFromExistingURI(AAIObjectType.VF_MODULE, UriBuilder.fromPath(queryAAIVfModuleRequest).build())
279 Optional<VfModule> vfModule = getAAIClient().get(VfModule.class,uri)
280 if(vfModule.isPresent()){
281 execution.setVariable('UPDVfModVol_personaModelId',vfModule.get().getModelInvariantId())
283 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "VF Module not found at AAI")
285 }catch(BpmnError bpmnError){
288 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Error in queryAAIForVfModule: "+e.getMessage())
293 * Prepare a Request for invoking the VnfAdapterRest subflow to do
294 * a Volume Group update.
296 * @param execution The flow's execution instance.
298 public void prepVnfAdapterRest(DelegateExecution execution, isDebugLogEnabled) {
300 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
301 def cloudOwner = execution.getVariable("UPDVfModVol_cloudRegion")
302 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
303 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
305 VolumeGroup aaiVolumeGroupResponse = execution.getVariable('UPDVfModVol_aaiVolumeGroupResponse')
306 def volumeGroupHeatStackId = aaiVolumeGroupResponse.getHeatStackId()
307 def volumeGroupName = aaiVolumeGroupResponse.getVolumeGroupName()
308 def modelCustomizationId = aaiVolumeGroupResponse.getModelCustomizationId()
310 def vnfType = execution.getVariable('UPDVfModVol_vnfType')
311 def vnfVersion = execution.getVariable('UPDVfModVol_vnfVersion')
313 GenericVnf aaiGenericVnfResponse = execution.getVariable('UPDVfModVol_AAIQueryGenericVfnResponse')
314 def vnfId = aaiGenericVnfResponse.getVnfId()
315 def vnfName = aaiGenericVnfResponse.getVnfName()
318 def volumeParamsXml = execution.getVariable('UPDVfModVol_volumeParams')
319 def volumeGroupParams = transformVolumeParamsToEntries(volumeParamsXml)
321 def requestId = execution.getVariable('UPDVfModVol_requestId')
322 def serviceId = execution.getVariable('UPDVfModVol_serviceId')
324 def messageId = execution.getVariable('mso-request-id') + '-' + System.currentTimeMillis()
325 def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
326 def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host", execution)
327 if ('true'.equals(useQualifiedHostName)) {
328 notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
331 String vnfAdapterRestRequest = """
332 <updateVolumeGroupRequest>
333 <cloudSiteId>${MsoUtils.xmlEscape(aicCloudRegion)}</cloudSiteId>
334 <cloudOwner>${MsoUtils.xmlEscape(cloudOwner)}</cloudOwner>
335 <tenantId>${MsoUtils.xmlEscape(tenantId)}</tenantId>
336 <vnfId>${MsoUtils.xmlEscape(vnfId)}</vnfId>
337 <vnfName>${MsoUtils.xmlEscape(vnfName)}</vnfName>
338 <volumeGroupId>${MsoUtils.xmlEscape(volumeGroupId)}</volumeGroupId>
339 <volumeGroupName>${MsoUtils.xmlEscape(volumeGroupName)}</volumeGroupName>
340 <volumeGroupStackId>${MsoUtils.xmlEscape(volumeGroupHeatStackId)}</volumeGroupStackId>
341 <vnfType>${MsoUtils.xmlEscape(vnfType)}</vnfType>
342 <vnfVersion>${MsoUtils.xmlEscape(vnfVersion)}</vnfVersion>
343 <vfModuleType></vfModuleType>
344 <modelCustomizationUuid>${MsoUtils.xmlEscape(modelCustomizationId)}</modelCustomizationUuid>
348 <value>${MsoUtils.xmlEscape(vnfId)}</value>
352 <value>${MsoUtils.xmlEscape(vnfName)}</value>
355 <key>vf_module_id</key>
356 <value>${MsoUtils.xmlEscape(volumeGroupId)}</value>
359 <key>vf_module_name</key>
360 <value>${MsoUtils.xmlEscape(volumeGroupName)}</value>
364 <skipAAI>true</skipAAI>
366 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
367 <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
369 <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
370 <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
371 </updateVolumeGroupRequest>
373 vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
374 execution.setVariable('UPDVfModVol_vnfAdapterRestRequest', vnfAdapterRestRequest)
375 logger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest)
379 * Prepare a Request for updating the DB for this Infra request.
381 * @param execution The flow's execution instance.
383 public void prepDbInfraDbRequest(DelegateExecution execution, isDebugLogEnabled) {
385 def requestId = execution.getVariable('UPDVfModVol_requestId')
387 String updateInfraRequest = """
388 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
389 xmlns:req="http://org.onap.so/requestsdb">
392 <req:updateInfraRequest>
393 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
394 <lastModifiedBy>BPEL</lastModifiedBy>
395 <requestStatus>COMPLETE</requestStatus>
396 <progress>100</progress>
397 </req:updateInfraRequest>
402 updateInfraRequest = utils.formatXml(updateInfraRequest)
403 execution.setVariable('UPDVfModVol_updateInfraRequest', updateInfraRequest)
404 logger.debug('Request for Update Infra Request:\n' + updateInfraRequest)
408 * Build a "CompletionHandler" request.
409 * @param execution The flow's execution instance.
411 public void prepCompletionHandlerRequest(DelegateExecution execution, requestId, action, source, isDebugLogEnabled) {
414 <aetgt:MsoCompletionRequest xmlns:aetgt="http://org.onap/so/workflow/schema/v1"
415 xmlns:ns="http://org.onap/so/request/types/v1">
416 <request-info xmlns="http://org.onap/so/infra/vnf-request/v1">
417 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
418 <action>UPDATE</action>
419 <source>${MsoUtils.xmlEscape(source)}</source>
421 <aetgt:mso-bpel-name>BPMN VF Module Volume action: UPDATE</aetgt:mso-bpel-name>
422 </aetgt:MsoCompletionRequest>
425 content = utils.formatXml(content)
426 logger.debug('Request for Completion Handler:\n' + content)
427 execution.setVariable('UPDVfModVol_CompletionHandlerRequest', content)
431 * Build a "FalloutHandler" request.
432 * @param execution The flow's execution instance.
434 public void prepFalloutHandler(DelegateExecution execution, isDebugLogEnabled) {
435 def requestId = execution.getVariable('UPDVfModVol_requestId')
436 def source = execution.getVariable('UPDVfModVol_source')
438 String requestInfo = """
439 <request-info xmlns="http://org.onap/so/infra/vnf-request/v1">
440 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
441 <action>UPDATE</action>
442 <source>${MsoUtils.xmlEscape(source)}</source>
445 WorkflowException workflowException = execution.getVariable("WorkflowException")
446 def errorResponseCode = workflowException.getErrorCode()
447 def errorResponseMsg = workflowException.getErrorMessage()
448 def encErrorResponseMsg = ""
449 if (errorResponseMsg != null) {
450 encErrorResponseMsg = errorResponseMsg
454 <sdncadapterworkflow:FalloutHandlerRequest xmlns:sdncadapterworkflow="http://org.onap/so/workflow/schema/v1"
455 xmlns:reqtype="http://org.onap/so/request/types/v1"
456 xmlns:msoservtypes="http://org.onap/so/request/types/v1"
457 xmlns:structuredtypes="http://org.onap/so/structured/types/v1">
459 <sdncadapterworkflow:WorkflowException>
460 <sdncadapterworkflow:ErrorMessage>${MsoUtils.xmlEscape(encErrorResponseMsg)}</sdncadapterworkflow:ErrorMessage>
461 <sdncadapterworkflow:ErrorCode>${MsoUtils.xmlEscape(errorResponseCode)}</sdncadapterworkflow:ErrorCode>
462 </sdncadapterworkflow:WorkflowException>
463 </sdncadapterworkflow:FalloutHandlerRequest>
465 content = utils.formatXml(content)
466 logger.debug('Request for Fallout Handler:\n' + content)
467 execution.setVariable('UPDVfModVol_FalloutHandlerRequest', content)
471 * Create a WorkflowException for the error case where the Tenant Id from
472 * AAI did not match the Tenant Id in the incoming request.
473 * @param execution The flow's execution instance.
475 public void handleTenantIdMismatch(DelegateExecution execution, isDebugLogEnabled) {
477 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
478 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
479 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
480 def volumeGroupTenantId = execution.getVariable('UPDVfModVol_volumeGroupTenantId')
482 String errorMessage = "TenantId " + tenantId + " in incoming request does not match Tenant Id " + volumeGroupTenantId +
483 " retrieved from AAI for Volume Group Id " + volumeGroupId + ", AIC Cloud Region " + aicCloudRegion
485 ExceptionUtil exceptionUtil = new ExceptionUtil()
486 logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), 'Error in ' +
487 'UpdateVfModuleVol: ' + errorMessage, "BPMN", ErrorCode.UnknownError.getValue(), "Exception")
488 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage)
492 * Create a WorkflowException for the error case where the Personal Model Id from
493 * AAI did not match the model invariant ID in the incoming request.
494 * @param execution The flow's execution instance.
496 public void handlePersonaModelIdMismatch(DelegateExecution execution, isDebugLogEnabled) {
498 def modelInvariantId = execution.getVariable('UPDVfModVol_modelInvariantId')
499 def personaModelId = execution.getVariable('UPDVfModVol_personaModelId')
501 String errorMessage = "Model Invariant ID " + modelInvariantId + " in incoming request does not match persona model ID " + personaModelId +
502 " retrieved from AAI for Volume Group Id "
504 ExceptionUtil exceptionUtil = new ExceptionUtil()
505 logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), 'Error in ' +
506 'UpdateVfModuleVol: ' + errorMessage, "BPMN", ErrorCode.UnknownError.getValue(), "Exception")
507 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage)