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 groovy.json.JsonException
26 import groovy.json.JsonSlurper
27 import org.camunda.bpm.engine.delegate.BpmnError
28 import org.camunda.bpm.engine.delegate.DelegateExecution
29 import org.onap.aai.domain.yang.GenericVnf
30 import org.onap.aai.domain.yang.VfModule
31 import org.onap.aai.domain.yang.VolumeGroup
32 import org.onap.so.bpmn.common.scripts.ExceptionUtil
33 import org.onap.so.bpmn.common.scripts.MsoUtils
34 import org.onap.so.bpmn.common.scripts.VfModuleBase
35 import org.onap.so.bpmn.common.scripts.VidUtils
36 import org.onap.so.bpmn.core.UrnPropertiesReader
37 import org.onap.so.bpmn.core.WorkflowException
38 import org.onap.so.client.aai.AAIObjectType
39 import org.onap.so.client.aai.entities.AAIResultWrapper
40 import org.onap.so.client.aai.entities.Relationships
41 import org.onap.so.client.aai.entities.uri.AAIResourceUri
42 import org.onap.so.client.aai.entities.uri.AAIUriFactory
43 import org.onap.so.constants.Defaults
44 import org.onap.so.logger.ErrorCode
45 import org.onap.so.logger.MessageEnum
46 import org.slf4j.Logger
47 import org.slf4j.LoggerFactory
49 import javax.ws.rs.core.UriBuilder
51 import static org.apache.cxf.common.util.CollectionUtils.isEmpty
53 class UpdateVfModuleVolumeInfraV1 extends VfModuleBase {
54 private static final Logger logger = LoggerFactory.getLogger(UpdateVfModuleVolumeInfraV1.class)
55 private ExceptionUtil exceptionUtil = new ExceptionUtil()
58 * Initialize the flow's variables.
60 * @param execution The flow's execution instance.
62 private void initProcessVariables(DelegateExecution execution) {
63 execution.setVariable('prefix', 'UPDVfModVol_')
64 execution.setVariable('UPDVfModVol_Request', null)
65 execution.setVariable('UPDVfModVol_requestInfo', null)
66 execution.setVariable('UPDVfModVol_requestId', null)
67 execution.setVariable('UPDVfModVol_source', null)
68 execution.setVariable('UPDVfModVol_volumeInputs', null)
69 execution.setVariable('UPDVfModVol_volumeGroupId', null)
70 execution.setVariable('UPDVfModVol_vnfType', null)
71 execution.setVariable('UPDVfModVol_serviceId', null)
72 execution.setVariable('UPDVfModVol_aicCloudRegion', null)
73 execution.setVariable('UPDVfModVol_tenantId', null)
74 execution.setVariable('UPDVfModVol_volumeParams', null)
75 execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', null)
76 execution.setVariable('UPDVfModVol_volumeGroupTenantId', null)
77 execution.setVariable('UpdateVfModuleVolumeSuccessIndicator', false)
81 * Perform initial processing, such as request validation, initialization of variables, etc.
84 public void preProcessRequest(DelegateExecution execution) {
85 def isDebugEnabled = execution.getVariable("isDebugLogEnabled")
86 preProcessRequest(execution, isDebugEnabled)
89 public void preProcessRequest(DelegateExecution execution, isDebugLogEnabled) {
91 initProcessVariables(execution)
92 String jsonRequest = validateRequest(execution)
97 def jsonSlurper = new JsonSlurper()
98 Map reqMap = jsonSlurper.parseText(jsonRequest)
100 def serviceInstanceId = execution.getVariable('serviceInstanceId')
101 def volumeGroupId = execution.getVariable('volumeGroupId')
102 //def vnfId = execution.getVariable('vnfId')
104 def vidUtils = new VidUtils(this)
105 request = vidUtils.createXmlVolumeRequest(reqMap, 'UPDATE_VF_MODULE_VOL', serviceInstanceId, volumeGroupId)
107 execution.setVariable('UPDVfModVol_Request', request)
108 execution.setVariable("UPDVfModVol_isVidRequest", true)
110 //need to get persona-model-id aka model-invariantId to use later to validate vf-module relation in AAI
112 def modelInvariantId = reqMap.requestDetails.modelInfo.modelInvariantUuid ?: ''
113 execution.setVariable('UPDVfModVol_modelInvariantId', modelInvariantId)
115 logger.debug("modelInvariantId from request: {}", modelInvariantId)
116 logger.debug("XML request:\n{}", request)
118 catch (JsonException je) {
119 logger.debug(" Request is in XML format.")
120 // assume request is in XML format - proceed as usual to process XML request
123 def requestId = execution.getVariable('mso-request-id')
125 def requestInfo = getRequiredNodeXml(execution, request, 'request-info')
126 execution.setVariable('UPDVfModVol_requestInfo', requestInfo)
127 execution.setVariable('UPDVfModVol_requestId', requestId)
128 //execution.setVariable('UPDVfModVol_requestId', getRequiredNodeText(execution, requestInfo, 'request-id'))
129 execution.setVariable('UPDVfModVol_source', getNodeTextForce(requestInfo, 'source'))
131 def volumeInputs = getRequiredNodeXml(execution, request, 'volume-inputs')
132 execution.setVariable('UPDVfModVol_volumeInputs', volumeInputs)
133 execution.setVariable('UPDVfModVol_volumeGroupId', getRequiredNodeText(execution, volumeInputs, 'volume-group-id'))
134 execution.setVariable('UPDVfModVol_vnfType', getRequiredNodeText(execution, volumeInputs, 'vnf-type'))
135 execution.setVariable('UPDVfModVol_vnfVersion', getRequiredNodeText(execution, volumeInputs, 'asdc-service-model-version'))
136 execution.setVariable('UPDVfModVol_serviceId', utils.getNodeText(volumeInputs, 'service-id'))
137 execution.setVariable('UPDVfModVol_aicCloudRegion', getRequiredNodeText(execution, volumeInputs, 'aic-cloud-region'))
138 execution.setVariable('UPDVfModVol_cloudRegion', getRequiredNodeText(execution, volumeInputs, 'cloud-owner'))
139 execution.setVariable('UPDVfModVol_tenantId', getRequiredNodeText(execution, volumeInputs, 'tenant-id'))
140 //execution.setVariable('UPDVfModVol_modelCustomizationId', getRequiredNodeText(execution, volumeInputs, 'model-customization-id'))
142 setBasicDBAuthHeader(execution, isDebugLogEnabled)
144 def volumeParams = utils.getNodeXml(request, 'volume-params')
145 execution.setVariable('UPDVfModVol_volumeParams', volumeParams)
149 * Prepare and send the synchronous response.
151 * @param execution The flow's execution instance.
153 public void sendSynchResponse(DelegateExecution execution, isDebugLogEnabled) {
155 def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
156 def requestId = execution.getVariable('UPDVfModVol_requestId')
157 def source = execution.getVariable('UPDVfModVol_source')
158 def progress = getNodeTextForce(requestInfo, 'progress')
159 if (progress.isEmpty()) {
162 def startTime = getNodeTextForce(requestInfo, 'start-time')
163 if (startTime.isEmpty()) {
164 startTime = System.currentTimeMillis()
166 def volumeInputs = execution.getVariable('UPDVfModVol_volumeInputs')
168 String xmlSyncResponse = """
169 <volume-request xmlns="http://org.onap/so/infra/vnf-request/v1">
171 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
172 <action>UPDATE_VF_MODULE_VOL</action>
173 <request-status>IN_PROGRESS</request-status>
174 <progress>${MsoUtils.xmlEscape(progress)}</progress>
175 <start-time>${MsoUtils.xmlEscape(startTime)}</start-time>
176 <source>${MsoUtils.xmlEscape(source)}</source>
182 def syncResponse = ''
183 def isVidRequest = execution.getVariable('UPDVfModVol_isVidRequest')
186 def volumeGroupId = execution.getVariable('volumeGroupId')
187 syncResponse = """{"requestReferences":{"instanceId":"${volumeGroupId}","requestId":"${
191 syncResponse = utils.formatXml(xmlSyncResponse)
194 logger.debug('Sync response: {}', syncResponse)
195 execution.setVariable('UPDVfModVol_syncResponseSent', true)
196 sendWorkflowResponse(execution, 200, syncResponse)
200 * Prepare a Request for querying AAI for Volume Group information using the
201 * Volume Group Id and Aic Cloud Region.
202 * @param execution The flow's execution instance.
204 public void queryAAIForVolumeGroup(DelegateExecution execution, isDebugLogEnabled) {
206 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
207 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
210 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(), aicCloudRegion, volumeGroupId)
211 AAIResultWrapper wrapper = getAAIClient().get(uri)
212 Optional<VolumeGroup> volumeGroup = wrapper.asBean(VolumeGroup.class)
213 if (volumeGroup.isPresent()) {
214 execution.setVariable('UPDVfModVol_aaiVolumeGroupResponse', volumeGroup.get())
215 Optional<Relationships> relationships = wrapper.getRelationships()
216 if (relationships.isPresent()) {
217 List<AAIResourceUri> tenantURIList = relationships.get().getRelatedAAIUris(AAIObjectType.TENANT)
218 if (!isEmpty(tenantURIList)) {
219 String volumeGroupTenantId = tenantURIList.get(0).getURIKeys().get("tenant-id")
220 execution.setVariable('UPDVfModVol_volumeGroupTenantId', volumeGroupTenantId)
221 logger.debug("Received Tenant Id {} from AAI for Volume Group with Volume Group Id {}, AIC Cloud Region ",
222 volumeGroupTenantId, volumeGroupId, aicCloudRegion)
224 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id " + volumeGroupId
225 + ", AIC Cloud Region " + aicCloudRegion)
227 execution.setVariable('UPDVfModVol_relatedVfModuleLink', relationships.get().getRelatedLinks(AAIObjectType.VF_MODULE).get(0))
230 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id " + volumeGroupId
231 + ", AIC Cloud Region " + aicCloudRegion)
234 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group " + volumeGroupId + " not found at AAI")
236 }catch(BpmnError bpmnError){
239 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - Occured During queryAAIForGenericVnf"+e.getMessage())
244 * Query AAI service instance
246 * @param isDebugEnabled
248 public void queryAAIForGenericVnf(DelegateExecution execution, isDebugEnabled) {
250 def vnfId = execution.getVariable('vnfId')
252 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId)
254 Optional<GenericVnf> genericVnf = getAAIClient().get(GenericVnf.class, uri)
255 if (genericVnf.isPresent()) {
256 execution.setVariable('UPDVfModVol_AAIQueryGenericVfnResponse', genericVnf.get())
258 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, 'Generic vnf ' + vnfId + ' was not found in AAI. Return code: 404.')
260 }catch(BpmnError bpmnError){
263 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - Occured During queryAAIForGenericVnf"+e.getMessage())
268 * Query AAI for VF Module using vf-module-id
270 * @param isDebugLogEnabled
272 public void queryAAIForVfModule(DelegateExecution execution, isDebugLogEnabled) {
274 String queryAAIVfModuleRequest = execution.getVariable('UPDVfModVol_relatedVfModuleLink')
275 execution.setVariable('UPDVfModVol_personaModelId', '')
276 AAIResourceUri uri = AAIUriFactory.createResourceFromExistingURI(AAIObjectType.VF_MODULE, UriBuilder.fromPath(queryAAIVfModuleRequest).build())
278 Optional<VfModule> vfModule = getAAIClient().get(VfModule.class,uri)
279 if(vfModule.isPresent()){
280 execution.setVariable('UPDVfModVol_personaModelId',vfModule.get().getModelInvariantId())
282 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "VF Module not found at AAI")
284 }catch(BpmnError bpmnError){
287 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Error in queryAAIForVfModule: "+e.getMessage())
292 * Prepare a Request for invoking the VnfAdapterRest subflow to do
293 * a Volume Group update.
295 * @param execution The flow's execution instance.
297 public void prepVnfAdapterRest(DelegateExecution execution, isDebugLogEnabled) {
299 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
300 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
301 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
303 VolumeGroup aaiVolumeGroupResponse = execution.getVariable('UPDVfModVol_aaiVolumeGroupResponse')
304 def volumeGroupHeatStackId = aaiVolumeGroupResponse.getHeatStackId()
305 def volumeGroupName = aaiVolumeGroupResponse.getVolumeGroupName()
306 def modelCustomizationId = aaiVolumeGroupResponse.getModelCustomizationId()
308 def vnfType = execution.getVariable('UPDVfModVol_vnfType')
309 def vnfVersion = execution.getVariable('UPDVfModVol_vnfVersion')
311 GenericVnf aaiGenericVnfResponse = execution.getVariable('UPDVfModVol_AAIQueryGenericVfnResponse')
312 def vnfId = aaiGenericVnfResponse.getVnfId()
313 def vnfName = aaiGenericVnfResponse.getVnfName()
316 def volumeParamsXml = execution.getVariable('UPDVfModVol_volumeParams')
317 def volumeGroupParams = transformVolumeParamsToEntries(volumeParamsXml)
319 def requestId = execution.getVariable('UPDVfModVol_requestId')
320 def serviceId = execution.getVariable('UPDVfModVol_serviceId')
322 def messageId = execution.getVariable('mso-request-id') + '-' + System.currentTimeMillis()
323 def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
324 def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host", execution)
325 if ('true'.equals(useQualifiedHostName)) {
326 notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
329 String vnfAdapterRestRequest = """
330 <updateVolumeGroupRequest>
331 <cloudSiteId>${MsoUtils.xmlEscape(aicCloudRegion)}</cloudSiteId>
332 <cloudOwner>${MsoUtils.xmlEscape(cloudOwner)}</cloudOwner>
333 <tenantId>${MsoUtils.xmlEscape(tenantId)}</tenantId>
334 <vnfId>${MsoUtils.xmlEscape(vnfId)}</vnfId>
335 <vnfName>${MsoUtils.xmlEscape(vnfName)}</vnfName>
336 <volumeGroupId>${MsoUtils.xmlEscape(volumeGroupId)}</volumeGroupId>
337 <volumeGroupName>${MsoUtils.xmlEscape(volumeGroupName)}</volumeGroupName>
338 <volumeGroupStackId>${MsoUtils.xmlEscape(volumeGroupHeatStackId)}</volumeGroupStackId>
339 <vnfType>${MsoUtils.xmlEscape(vnfType)}</vnfType>
340 <vnfVersion>${MsoUtils.xmlEscape(vnfVersion)}</vnfVersion>
341 <vfModuleType></vfModuleType>
342 <modelCustomizationUuid>${MsoUtils.xmlEscape(modelCustomizationId)}</modelCustomizationUuid>
346 <value>${MsoUtils.xmlEscape(vnfId)}</value>
350 <value>${MsoUtils.xmlEscape(vnfName)}</value>
353 <key>vf_module_id</key>
354 <value>${MsoUtils.xmlEscape(volumeGroupId)}</value>
357 <key>vf_module_name</key>
358 <value>${MsoUtils.xmlEscape(volumeGroupName)}</value>
362 <skipAAI>true</skipAAI>
364 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
365 <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
367 <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
368 <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
369 </updateVolumeGroupRequest>
371 vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
372 execution.setVariable('UPDVfModVol_vnfAdapterRestRequest', vnfAdapterRestRequest)
373 logger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest)
377 * Prepare a Request for updating the DB for this Infra request.
379 * @param execution The flow's execution instance.
381 public void prepDbInfraDbRequest(DelegateExecution execution, isDebugLogEnabled) {
383 def requestId = execution.getVariable('UPDVfModVol_requestId')
385 String updateInfraRequest = """
386 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
387 xmlns:req="http://org.onap.so/requestsdb">
390 <req:updateInfraRequest>
391 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
392 <lastModifiedBy>BPEL</lastModifiedBy>
393 <requestStatus>COMPLETE</requestStatus>
394 <progress>100</progress>
395 </req:updateInfraRequest>
400 updateInfraRequest = utils.formatXml(updateInfraRequest)
401 execution.setVariable('UPDVfModVol_updateInfraRequest', updateInfraRequest)
402 logger.debug('Request for Update Infra Request:\n' + updateInfraRequest)
406 * Build a "CompletionHandler" request.
407 * @param execution The flow's execution instance.
409 public void prepCompletionHandlerRequest(DelegateExecution execution, requestId, action, source, isDebugLogEnabled) {
412 <aetgt:MsoCompletionRequest xmlns:aetgt="http://org.onap/so/workflow/schema/v1"
413 xmlns:ns="http://org.onap/so/request/types/v1">
414 <request-info xmlns="http://org.onap/so/infra/vnf-request/v1">
415 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
416 <action>UPDATE</action>
417 <source>${MsoUtils.xmlEscape(source)}</source>
419 <aetgt:mso-bpel-name>BPMN VF Module Volume action: UPDATE</aetgt:mso-bpel-name>
420 </aetgt:MsoCompletionRequest>
423 content = utils.formatXml(content)
424 logger.debug('Request for Completion Handler:\n' + content)
425 execution.setVariable('UPDVfModVol_CompletionHandlerRequest', content)
429 * Build a "FalloutHandler" request.
430 * @param execution The flow's execution instance.
432 public void prepFalloutHandler(DelegateExecution execution, isDebugLogEnabled) {
433 def requestId = execution.getVariable('UPDVfModVol_requestId')
434 def source = execution.getVariable('UPDVfModVol_source')
436 String requestInfo = """
437 <request-info xmlns="http://org.onap/so/infra/vnf-request/v1">
438 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
439 <action>UPDATE</action>
440 <source>${MsoUtils.xmlEscape(source)}</source>
443 WorkflowException workflowException = execution.getVariable("WorkflowException")
444 def errorResponseCode = workflowException.getErrorCode()
445 def errorResponseMsg = workflowException.getErrorMessage()
446 def encErrorResponseMsg = ""
447 if (errorResponseMsg != null) {
448 encErrorResponseMsg = errorResponseMsg
452 <sdncadapterworkflow:FalloutHandlerRequest xmlns:sdncadapterworkflow="http://org.onap/so/workflow/schema/v1"
453 xmlns:reqtype="http://org.onap/so/request/types/v1"
454 xmlns:msoservtypes="http://org.onap/so/request/types/v1"
455 xmlns:structuredtypes="http://org.onap/so/structured/types/v1">
457 <sdncadapterworkflow:WorkflowException>
458 <sdncadapterworkflow:ErrorMessage>${MsoUtils.xmlEscape(encErrorResponseMsg)}</sdncadapterworkflow:ErrorMessage>
459 <sdncadapterworkflow:ErrorCode>${MsoUtils.xmlEscape(errorResponseCode)}</sdncadapterworkflow:ErrorCode>
460 </sdncadapterworkflow:WorkflowException>
461 </sdncadapterworkflow:FalloutHandlerRequest>
463 content = utils.formatXml(content)
464 logger.debug('Request for Fallout Handler:\n' + content)
465 execution.setVariable('UPDVfModVol_FalloutHandlerRequest', content)
469 * Create a WorkflowException for the error case where the Tenant Id from
470 * AAI did not match the Tenant Id in the incoming request.
471 * @param execution The flow's execution instance.
473 public void handleTenantIdMismatch(DelegateExecution execution, isDebugLogEnabled) {
475 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
476 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
477 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
478 def volumeGroupTenantId = execution.getVariable('UPDVfModVol_volumeGroupTenantId')
480 String errorMessage = "TenantId " + tenantId + " in incoming request does not match Tenant Id " + volumeGroupTenantId +
481 " retrieved from AAI for Volume Group Id " + volumeGroupId + ", AIC Cloud Region " + aicCloudRegion
483 ExceptionUtil exceptionUtil = new ExceptionUtil()
484 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), 'Error in ' +
485 'UpdateVfModuleVol: ' + errorMessage, "BPMN", ErrorCode.UnknownError.getValue(), "Exception")
486 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage)
490 * Create a WorkflowException for the error case where the Personal Model Id from
491 * AAI did not match the model invariant ID in the incoming request.
492 * @param execution The flow's execution instance.
494 public void handlePersonaModelIdMismatch(DelegateExecution execution, isDebugLogEnabled) {
496 def modelInvariantId = execution.getVariable('UPDVfModVol_modelInvariantId')
497 def personaModelId = execution.getVariable('UPDVfModVol_personaModelId')
499 String errorMessage = "Model Invariant ID " + modelInvariantId + " in incoming request does not match persona model ID " + personaModelId +
500 " retrieved from AAI for Volume Group Id "
502 ExceptionUtil exceptionUtil = new ExceptionUtil()
503 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), 'Error in ' +
504 'UpdateVfModuleVol: ' + errorMessage, "BPMN", ErrorCode.UnknownError.getValue(), "Exception")
505 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage)