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.apache.commons.collections.CollectionUtils
 
  26 import org.camunda.bpm.engine.delegate.BpmnError
 
  27 import org.camunda.bpm.engine.delegate.DelegateExecution
 
  28 import org.onap.aai.domain.yang.VolumeGroup
 
  29 import org.onap.so.bpmn.common.scripts.ExceptionUtil
 
  30 import org.onap.so.bpmn.common.scripts.MsoUtils
 
  31 import org.onap.so.bpmn.common.scripts.VfModuleBase
 
  32 import org.onap.so.bpmn.core.UrnPropertiesReader
 
  33 import org.onap.so.bpmn.core.WorkflowException
 
  34 import org.onap.so.client.aai.AAIObjectType
 
  35 import org.onap.so.client.aai.entities.AAIResultWrapper
 
  36 import org.onap.so.client.aai.entities.Relationships
 
  37 import org.onap.so.client.aai.entities.uri.AAIResourceUri
 
  38 import org.onap.so.client.aai.entities.uri.AAIUriFactory
 
  39 import org.onap.so.constants.Defaults
 
  40 import org.onap.logging.filter.base.ErrorCode
 
  41 import org.onap.so.logger.MessageEnum
 
  42 import org.slf4j.Logger
 
  43 import org.slf4j.LoggerFactory
 
  45 import static org.apache.commons.lang.StringUtils.isEmpty
 
  47 class UpdateVfModuleVolume extends VfModuleBase {
 
  48     private static final Logger logger = LoggerFactory.getLogger(UpdateVfModuleVolume.class)
 
  50         ExceptionUtil exceptionUtil = new ExceptionUtil()
 
  53          * Initialize the flow's variables.
 
  55          * @param execution The flow's execution instance.
 
  57         private void initProcessVariables(DelegateExecution execution) {
 
  58                 execution.setVariable('prefix', 'UPDVfModVol_')
 
  59                 execution.setVariable('UPDVfModVol_Request', null)
 
  60                 execution.setVariable('UPDVfModVol_requestInfo', null)
 
  61                 execution.setVariable('UPDVfModVol_requestId', null)
 
  62                 execution.setVariable('UPDVfModVol_source', null)
 
  63                 execution.setVariable('UPDVfModVol_volumeInputs', null)
 
  64                 execution.setVariable('UPDVfModVol_volumeGroupId', null)
 
  65                 execution.setVariable('UPDVfModVol_vnfType', null)
 
  66                 execution.setVariable('UPDVfModVol_serviceId', null)
 
  67                 execution.setVariable('UPDVfModVol_aicCloudRegion', null)
 
  68                 execution.setVariable('UPDVfModVol_tenantId', null)
 
  69                 execution.setVariable('UPDVfModVol_volumeParams', null)
 
  70                 execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', null)
 
  71                 execution.setVariable('UPDVfModVol_volumeGroupTenantId', null)
 
  72                 execution.setVariable('UpdateVfModuleVolumeSuccessIndicator', false)
 
  76          * Check for missing elements in the received request.
 
  78          * @param execution The flow's execution instance.
 
  81         public void preProcessRequest(DelegateExecution execution) {
 
  82                 def method = getClass().getSimpleName() + '.preProcessRequest(' +
 
  83                         'execution=' + execution.getId() +
 
  86         logger.trace('Entered {}', method)
 
  89                         initProcessVariables(execution)
 
  90                         String request = validateRequest(execution)
 
  92                         def requestInfo = getRequiredNodeXml(execution, request, 'request-info')
 
  93                         execution.setVariable('UPDVfModVol_requestInfo', requestInfo)
 
  94                         execution.setVariable('UPDVfModVol_requestId', getRequiredNodeText(execution, requestInfo, 'request-id'))
 
  95                         execution.setVariable('UPDVfModVol_source', getNodeTextForce(requestInfo, 'source'))
 
  97                         def volumeInputs = getRequiredNodeXml(execution, request, 'volume-inputs')
 
  98                         execution.setVariable('UPDVfModVol_volumeInputs', volumeInputs)
 
  99                         execution.setVariable('UPDVfModVol_volumeGroupId', getRequiredNodeText(execution, volumeInputs, 'volume-group-id'))
 
 100                         execution.setVariable('UPDVfModVol_vnfType', getRequiredNodeText(execution, volumeInputs, 'vnf-type'))
 
 101                         execution.setVariable('UPDVfModVol_serviceId', getRequiredNodeText(execution, volumeInputs, 'service-id'))
 
 102                         execution.setVariable('UPDVfModVol_aicCloudRegion', getRequiredNodeText(execution, volumeInputs, 'aic-cloud-region'))
 
 103                         execution.setVariable('UPDVfModVol_cloudOwner', getRequiredNodeText(execution, volumeInputs, 'cloud-owner'))
 
 104                         execution.setVariable('UPDVfModVol_tenantId', getRequiredNodeText(execution, volumeInputs, 'tenant-id'))
 
 106                         def volumeParams = utils.getNodeXml(request, 'volume-params')
 
 107                         execution.setVariable('UPDVfModVol_volumeParams', volumeParams)
 
 109             logger.trace('Exited {}', method)
 
 110             logger.debug("UpdateVfModuleVolume request: {}", request)
 
 111                 } catch (BpmnError bpmnError) {
 
 113                 } catch (Exception e) {
 
 114             logger.error("{} {} Caught exception in {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 115                     ErrorCode.UnknownError.getValue(), method, e)
 
 116                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in preProcessRequest(): ' + e.getMessage())
 
 121          * Prepare and send the synchronous response.
 
 123          * @param execution The flow's execution instance.
 
 125         public void sendSynchResponse(DelegateExecution execution) {
 
 126                 def method = getClass().getSimpleName() + '.sendSynchResponse(' +
 
 127                         'execution=' + execution.getId() +
 
 130         logger.trace('Entered {}', method)
 
 133                         def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
 
 134                         def requestId = execution.getVariable('UPDVfModVol_requestId')
 
 135                         def source = execution.getVariable('UPDVfModVol_source')
 
 136                         def progress = getNodeTextForce(requestInfo, 'progress')
 
 137                         if (progress.isEmpty()) {
 
 140                         def startTime = getNodeTextForce(requestInfo, 'start-time')
 
 141                         if (startTime.isEmpty()) {
 
 142                                 startTime = System.currentTimeMillis()
 
 144                         def volumeInputs = execution.getVariable('UPDVfModVol_volumeInputs')
 
 146                         String synchResponse = """
 
 147                                 <volume-request xmlns="http://org.onap/so/infra/vnf-request/v1">
 
 149                                                 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
 
 150                                                 <action>UPDATE_VF_MODULE_VOL</action>
 
 151                                                 <request-status>IN_PROGRESS</request-status>
 
 152                                                 <progress>${MsoUtils.xmlEscape(progress)}</progress>
 
 153                                                 <start-time>${MsoUtils.xmlEscape(startTime)}</start-time>
 
 154                                                 <source>${MsoUtils.xmlEscape(source)}</source>
 
 160                         synchResponse = utils.formatXml(synchResponse)
 
 161                         sendWorkflowResponse(execution, 200, synchResponse)
 
 162             logger.debug("UpdateVfModuleVolume Synch Response: {}", synchResponse)
 
 163                 } catch (BpmnError e) {
 
 165                 } catch (Exception e) {
 
 166             logger.error("{} {} Caught exception in {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 167                     ErrorCode.UnknownError.getValue(), method, e)
 
 168                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in sendSynchResponse(): ' + e.getMessage())
 
 173          * Prepare a Request for querying AAI for Volume Group information using the
 
 174          * Volume Group Id and Aic Cloud Region.
 
 176          * @param execution The flow's execution instance.
 
 178         public void queryAAIForVolumeGroup(DelegateExecution execution) {
 
 179                 def method = getClass().getSimpleName() + '.queryAAIForVolumeGroup(' +
 
 180                         'execution=' + execution.getId() +
 
 183         logger.trace('Entered {}', method)
 
 186                         def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
 
 187                         def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
 
 188                         AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(),aicCloudRegion,volumeGroupId)
 
 189                         AAIResultWrapper wrapper =  getAAIClient().get(uri)
 
 190                         Optional<VolumeGroup> volumeGroup = wrapper.asBean(VolumeGroup.class)
 
 191                         if(volumeGroup.isPresent()){
 
 192                                 def heatStackId = volumeGroup.get().getHeatStackId()
 
 193                                 execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', heatStackId)
 
 194                                 Optional<Relationships> relationships = wrapper.getRelationships()
 
 195                                 if(relationships.isPresent()){
 
 196                                         List<AAIResourceUri> resourceUriList = relationships.get().getRelatedAAIUris(AAIObjectType.TENANT)
 
 197                                         if(CollectionUtils.isNotEmpty(resourceUriList)){
 
 198                                                 AAIResourceUri tenantUri = resourceUriList.get(0)
 
 199                                                 String volumeGroupTenantId = tenantUri.getURIKeys().get("tenant-id")
 
 200                                                 if( isEmpty(volumeGroupTenantId)){
 
 201                                                         exceptionUtil.buildAndThrowWorkflowException(execution,2500,"Could not find Tenant Id element in Volume Group with Volume Group Id" + volumeGroupId + ", AIC Cloud Region" + aicCloudRegion)
 
 203                                                 execution.setVariable('UPDVfModVol_volumeGroupTenantId', volumeGroupTenantId)
 
 204                         logger.debug("Received Tenant Id: {} from AAI for Volume Group with Volume Group Id: {}, AIC Cloud Region",
 
 205                                 volumeGroupTenantId, volumeGroupId, aicCloudRegion)
 
 207                                                 exceptionUtil.buildAndThrowWorkflowException(execution,2500,"Could not find Tenant Id element in Volume Group with Volume Group Id" + volumeGroupId + ", AIC Cloud Region" + aicCloudRegion)
 
 211                                 exceptionUtil.buildAndThrowWorkflowException(execution,2500,"Volume Group" + volumeGroupId + " not found at AAI")
 
 213             logger.trace('Exited {}', method)
 
 214                 } catch (BpmnError e) {
 
 216                 } catch (Exception e) {
 
 217             logger.error("{} {} Caught exception in {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 218                     ErrorCode.UnknownError.getValue(), method, e)
 
 219                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in queryAAIForVolumeGroup(): ' + e.getMessage())
 
 224          * Prepare a Request for invoking the VnfAdapterRest subflow to do
 
 225          * a Volume Group update.
 
 227          * @param execution The flow's execution instance.
 
 229         public void prepVnfAdapterRest(DelegateExecution execution) {
 
 230                 def method = getClass().getSimpleName() + '.prepVnfAdapterRest(' +
 
 231                         'execution=' + execution.getId() +
 
 234         logger.trace('Entered {}', method)
 
 237                         def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
 
 238                         def tenantId = execution.getVariable('UPDVfModVol_tenantId')
 
 239                         def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
 
 240                         def volumeGroupHeatStackId = execution.getVariable('UPDVfModVol_volumeGroupHeatStackId')
 
 241                         def vnfType = execution.getVariable('UPDVfModVol_vnfType')
 
 243                         def volumeParamsXml = execution.getVariable('UPDVfModVol_volumeParams')
 
 244                         def volumeGroupParams = transformParamsToEntries(volumeParamsXml)
 
 246                         def requestId = execution.getVariable('UPDVfModVol_requestId')
 
 247                         def serviceId = execution.getVariable('UPDVfModVol_serviceId')
 
 249                         def messageId = execution.getVariable('mso-request-id') + '-' + System.currentTimeMillis()
 
 250                         def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
 
 251                         def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host",execution)
 
 252                         if ('true'.equals(useQualifiedHostName)) {
 
 253                                         notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
 
 256                         String vnfAdapterRestRequest = """
 
 257                                 <updateVolumeGroupRequest>
 
 258                                         <cloudSiteId>${MsoUtils.xmlEscape(aicCloudRegion)}</cloudSiteId>
 
 259                                         <cloudOwner>${MsoUtils.xmlEscape(cloudOwner)}</cloudOwner>
 
 260                                         <tenantId>${MsoUtils.xmlEscape(tenantId)}</tenantId>
 
 261                                         <volumeGroupId>${MsoUtils.xmlEscape(volumeGroupId)}</volumeGroupId>
 
 262                                         <volumeGroupStackId>${MsoUtils.xmlEscape(volumeGroupHeatStackId)}</volumeGroupStackId>
 
 263                                         <vnfType>${MsoUtils.xmlEscape(vnfType)}</vnfType>
 
 264                                         <vnfVersion></vnfVersion>
 
 265                                         <vfModuleType></vfModuleType>
 
 269                                         <skipAAI>true</skipAAI>
 
 271                                         <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
 
 272                                         <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
 
 274                                     <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
 
 275                                     <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
 
 276                                 </updateVolumeGroupRequest>
 
 278                         vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
 
 279                         execution.setVariable('UPDVfModVol_vnfAdapterRestRequest', vnfAdapterRestRequest)
 
 280             logger.debug('Request for VNFAdapter Rest:\n{}', vnfAdapterRestRequest)
 
 282             logger.debug("UpdateVfModuleVolume Request for VNFAdapter Rest: {}", vnfAdapterRestRequest)
 
 283             logger.trace('Exited {}', method)
 
 284                 } catch (BpmnError e) {
 
 286                 } catch (Exception e) {
 
 287             logger.error("{} {} Caught exception in {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 288                     ErrorCode.UnknownError.getValue(), method, e)
 
 289                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in prepVnfAdapterRest(): ' + e.getMessage())
 
 294          * Prepare a Request for updating the DB for this Infra request.
 
 296          * @param execution The flow's execution instance.
 
 298         public void prepDbInfraDbRequest(DelegateExecution execution) {
 
 299                 def method = getClass().getSimpleName() + '.prepDbInfraDbRequest(' +
 
 300                         'execution=' + execution.getId() +
 
 303         logger.trace('Entered {}', method)
 
 306                         def requestId = execution.getVariable('UPDVfMod_requestId')
 
 308                         String updateInfraRequest = """
 
 309                                 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 
 310                                                 xmlns:req="http://org.onap.so/requestsdb">
 
 313                                                 <req:updateInfraRequest>
 
 314                                                         <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
 
 315                                                         <lastModifiedBy>BPEL</lastModifiedBy>
 
 316                                                         <requestStatus>COMPLETE</requestStatus>
 
 317                                                         <progress>100</progress>
 
 318                                                 </req:updateInfraRequest>
 
 323                         updateInfraRequest = utils.formatXml(updateInfraRequest)
 
 324                         execution.setVariable('UPDVfModVol_updateInfraRequest', updateInfraRequest)
 
 325             logger.debug('Request for Update Infra Request:\n{}', updateInfraRequest)
 
 327             logger.debug("UpdateVfModuleVolume Request for Updating DB for Infra: {}", updateInfraRequest)
 
 328             logger.trace('Exited {}', method)
 
 329                 } catch (BpmnError e) {
 
 331                 } catch (Exception e) {
 
 332             logger.error("{} {} Caught exception in {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 333                     ErrorCode.UnknownError.getValue(), method, e)
 
 334                         exceptionUtil.buildWorkflowException(execution, 1002, 'Error in prepDbInfraDbRequest(): ' + e.getMessage())
 
 339          * Build a "CompletionHandler" request.
 
 341          * @param execution The flow's execution instance.
 
 343         public void prepCompletionHandlerRequest(DelegateExecution execution) {
 
 344                 def method = getClass().getSimpleName() + '.prepCompletionHandlerRequest(' +
 
 345                         'execution=' + execution.getId() +
 
 348         logger.trace('Entered {}', method)
 
 351                         def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
 
 354                                 <sdncadapterworkflow:MsoCompletionRequest xmlns:sdncadapterworkflow="http://org.onap/so/workflow/schema/v1"
 
 355                                                 xmlns:reqtype="http://org.onap/so/request/types/v1">
 
 357                                         <sdncadapterworkflow:mso-bpel-name>MSO_ACTIVATE_BPEL</sdncadapterworkflow:mso-bpel-name>
 
 358                                 </sdncadapterworkflow:MsoCompletionRequest>
 
 361                         content = utils.formatXml(content)
 
 362             logger.debug('Request for Completion Handler:\n{}', content)
 
 363             logger.debug("UpdateVfModuleVolume Completion Handler request: {}", content)
 
 364                         execution.setVariable('UPDVfModVol_CompletionHandlerRequest', content)
 
 366             logger.trace('Exited {}', method)
 
 367                 } catch (BpmnError e) {
 
 369                 } catch (Exception e) {
 
 370             logger.error("{} {} Caught exception in {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 371                     ErrorCode.UnknownError.getValue(), method, e)
 
 372                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in prepCompletionHandlerRequest(): ' + e.getMessage())
 
 377          * Build a "FalloutHandler" request.
 
 379          * @param execution The flow's execution instance.
 
 381         public void prepFalloutHandler(DelegateExecution execution) {
 
 382                 def method = getClass().getSimpleName() + '.prepFalloutHandler(' +
 
 383                         'execution=' + execution.getId() +
 
 386         logger.trace('Entered {}', method)
 
 389                         def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
 
 391                         def WorkflowException workflowException = execution.getVariable("WorkflowException")
 
 392                         def errorResponseCode = workflowException.getErrorCode()
 
 393                         def errorResponseMsg = workflowException.getErrorMessage()
 
 394                         def encErrorResponseMsg = ""
 
 395                         if (errorResponseMsg != null) {
 
 396                                 encErrorResponseMsg = errorResponseMsg
 
 400                                 <sdncadapterworkflow:FalloutHandlerRequest xmlns:sdncadapterworkflow="http://org.onap/so/workflow/schema/v1"
 
 401                                                 xmlns:reqtype="http://org.onap/so/request/types/v1"
 
 402                                                 xmlns:msoservtypes="http://org.onap/so/request/types/v1"
 
 403                                                 xmlns:structuredtypes="http://org.onap/so/structured/types/v1">
 
 405                                         <sdncadapterworkflow:WorkflowException>
 
 406                                                 <sdncadapterworkflow:ErrorMessage>${MsoUtils.xmlEscape(encErrorResponseMsg)}</sdncadapterworkflow:ErrorMessage>
 
 407                                                 <sdncadapterworkflow:ErrorCode>${MsoUtils.xmlEscape(errorResponseCode)}</sdncadapterworkflow:ErrorCode>
 
 408                                         </sdncadapterworkflow:WorkflowException>
 
 409                                 </sdncadapterworkflow:FalloutHandlerRequest>
 
 411                         content = utils.formatXml(content)
 
 412             logger.debug('Request for Fallout Handler:\n{}', content)
 
 413             logger.debug("UpdateVfModuleVolume Fallout request: {}", content)
 
 414                         execution.setVariable('UPDVfModVol_FalloutHandlerRequest', content)
 
 416             logger.trace('Exited {}', method)
 
 417                 } catch (BpmnError e) {
 
 419                 } catch (Exception e) {
 
 420             logger.error("{} {} Caught exception in {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 421                     ErrorCode.UnknownError.getValue(), method, e)
 
 422                         exceptionUtil.buildWorkflowException(execution, 1002, 'Error in prepFalloutHandler(): ' + e.getMessage())
 
 427          * Create a WorkflowException for the error case where the Tenant Id from
 
 428          * AAI did not match the Tenant Id in the incoming request.
 
 430          * @param execution The flow's execution instance.
 
 432         public void handleTenantIdMismatch(DelegateExecution execution) {
 
 433                 def method = getClass().getSimpleName() + '.handleTenantIdMismatch(' +
 
 434                         'execution=' + execution.getId() +
 
 437         logger.trace('Entered {}', method)
 
 439                 String processKey = getProcessKey(execution)
 
 440                 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
 
 441                 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
 
 442                 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
 
 443                 def volumeGroupTenantId = execution.getVariable('UPDVfModVol_volumeGroupTenantId')
 
 445                 def String errorMessage = 'TenantId \'' + tenantId + '\' in incoming request does not match Tenant Id \'' + volumeGroupTenantId +
 
 446                         '\' retrieved from AAI for Volume Group Id \'' + volumeGroupId + '\', AIC Cloud Region \'' + aicCloudRegion + '\''
 
 448                 logger.error("{} {} Error in UpdateVfModuleVol: {}\n ", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
 
 449                 ErrorCode.UnknownError.getValue(), errorMessage)
 
 451                 WorkflowException exception = new WorkflowException(processKey, 5000, errorMessage)
 
 452                 execution.setVariable("WorkflowException", exception)
 
 454                 logger.trace('Exited ' + method)
 
 455                 logger.debug("UpdateVfModuleVolume workflowException in Tenant Mismatch: " + errorMessage)