/*- * ============LICENSE_START======================================================= * ONAP - SO * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.onap.so.bpmn.infrastructure.scripts import org.apache.commons.lang3.* import org.camunda.bpm.engine.delegate.BpmnError import org.camunda.bpm.engine.delegate.DelegateExecution import org.onap.so.bpmn.common.scripts.AaiUtil; import org.onap.so.bpmn.common.scripts.ExceptionUtil; import org.onap.so.bpmn.common.scripts.MsoUtils import org.onap.so.bpmn.common.scripts.VfModuleBase; import org.onap.so.bpmn.common.scripts.VidUtils; import org.onap.so.bpmn.core.UrnPropertiesReader import org.onap.so.bpmn.core.WorkflowException import org.onap.so.logger.MessageEnum import org.onap.so.logger.MsoLogger import org.onap.so.rest.APIResponse import org.springframework.web.util.UriUtils import groovy.json.JsonSlurper class UpdateVfModuleVolumeInfraV1 extends VfModuleBase { private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, UpdateVfModuleVolumeInfraV1.class); /** * Initialize the flow's variables. * * @param execution The flow's execution instance. */ private void initProcessVariables(DelegateExecution execution) { execution.setVariable('prefix', 'UPDVfModVol_') execution.setVariable('UPDVfModVol_Request', null) execution.setVariable('UPDVfModVol_requestInfo', null) execution.setVariable('UPDVfModVol_requestId', null) execution.setVariable('UPDVfModVol_source', null) execution.setVariable('UPDVfModVol_volumeInputs', null) execution.setVariable('UPDVfModVol_volumeGroupId', null) execution.setVariable('UPDVfModVol_vnfType', null) execution.setVariable('UPDVfModVol_serviceId', null) execution.setVariable('UPDVfModVol_aicCloudRegion', null) execution.setVariable('UPDVfModVol_tenantId', null) execution.setVariable('UPDVfModVol_volumeParams', null) execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', null) execution.setVariable('UPDVfModVol_volumeGroupTenantId', null) execution.setVariable('UpdateVfModuleVolumeSuccessIndicator', false) } /** * Perform initial processing, such as request validation, initialization of variables, etc. * * @param execution */ public void preProcessRequest (DelegateExecution execution) { def isDebugEnabled=execution.getVariable("isDebugLogEnabled") preProcessRequest(execution, isDebugEnabled) } public void preProcessRequest(DelegateExecution execution, isDebugLogEnabled) { initProcessVariables(execution) String jsonRequest = validateRequest(execution) def request = "" try { def jsonSlurper = new JsonSlurper() Map reqMap = jsonSlurper.parseText(jsonRequest) def serviceInstanceId = execution.getVariable('serviceInstanceId') def volumeGroupId = execution.getVariable('volumeGroupId') //def vnfId = execution.getVariable('vnfId') def vidUtils = new VidUtils(this) request = vidUtils.createXmlVolumeRequest(reqMap, 'UPDATE_VF_MODULE_VOL', serviceInstanceId, volumeGroupId) execution.setVariable('UPDVfModVol_Request', request) execution.setVariable("UPDVfModVol_isVidRequest", true) //need to get persona-model-id aka model-invariantId to use later to validate vf-module relation in AAI def modelInvariantId = reqMap.requestDetails.modelInfo.modelInvariantUuid ?: '' execution.setVariable('UPDVfModVol_modelInvariantId', modelInvariantId) msoLogger.debug("modelInvariantId from request: " + modelInvariantId) msoLogger.debug("XML request:\n" + request) } catch(groovy.json.JsonException je) { msoLogger.debug(" Request is in XML format.") // assume request is in XML format - proceed as usual to process XML request } def requestId = execution.getVariable('mso-request-id') def requestInfo = getRequiredNodeXml(execution, request, 'request-info') execution.setVariable('UPDVfModVol_requestInfo', requestInfo) execution.setVariable('UPDVfModVol_requestId', requestId) //execution.setVariable('UPDVfModVol_requestId', getRequiredNodeText(execution, requestInfo, 'request-id')) execution.setVariable('UPDVfModVol_source', getNodeTextForce(requestInfo, 'source')) def volumeInputs = getRequiredNodeXml(execution, request, 'volume-inputs') execution.setVariable('UPDVfModVol_volumeInputs', volumeInputs) execution.setVariable('UPDVfModVol_volumeGroupId', getRequiredNodeText(execution, volumeInputs, 'volume-group-id')) execution.setVariable('UPDVfModVol_vnfType', getRequiredNodeText(execution, volumeInputs, 'vnf-type')) execution.setVariable('UPDVfModVol_vnfVersion', getRequiredNodeText(execution, volumeInputs, 'asdc-service-model-version')) execution.setVariable('UPDVfModVol_serviceId', utils.getNodeText(volumeInputs, 'service-id')) execution.setVariable('UPDVfModVol_aicCloudRegion', getRequiredNodeText(execution, volumeInputs, 'aic-cloud-region')) execution.setVariable('UPDVfModVol_tenantId', getRequiredNodeText(execution, volumeInputs, 'tenant-id')) //execution.setVariable('UPDVfModVol_modelCustomizationId', getRequiredNodeText(execution, volumeInputs, 'model-customization-id')) setBasicDBAuthHeader(execution, isDebugLogEnabled) def volumeParams = utils.getNodeXml(request, 'volume-params') execution.setVariable('UPDVfModVol_volumeParams', volumeParams) } /** * Prepare and send the synchronous response. * * @param execution The flow's execution instance. */ public void sendSynchResponse(DelegateExecution execution, isDebugLogEnabled) { def requestInfo = execution.getVariable('UPDVfModVol_requestInfo') def requestId = execution.getVariable('UPDVfModVol_requestId') def source = execution.getVariable('UPDVfModVol_source') def progress = getNodeTextForce(requestInfo, 'progress') if (progress.isEmpty()) { progress = '0' } def startTime = getNodeTextForce(requestInfo, 'start-time') if (startTime.isEmpty()) { startTime = System.currentTimeMillis() } def volumeInputs = execution.getVariable('UPDVfModVol_volumeInputs') String xmlSyncResponse = """ ${MsoUtils.xmlEscape(requestId)} UPDATE_VF_MODULE_VOL IN_PROGRESS ${MsoUtils.xmlEscape(progress)} ${MsoUtils.xmlEscape(startTime)} ${MsoUtils.xmlEscape(source)} ${volumeInputs} """ def syncResponse = '' def isVidRequest = execution.getVariable('UPDVfModVol_isVidRequest') if(isVidRequest) { def volumeGroupId = execution.getVariable('volumeGroupId') syncResponse = """{"requestReferences":{"instanceId":"${volumeGroupId}","requestId":"${requestId}"}}""".trim() } else { syncResponse = utils.formatXml(xmlSyncResponse) } msoLogger.debug('Sync response: ' + syncResponse) execution.setVariable('UPDVfModVol_syncResponseSent', true) sendWorkflowResponse(execution, 200, syncResponse) } /** * Prepare a Request for querying AAI for Volume Group information using the * Volume Group Id and Aic Cloud Region. * @param execution The flow's execution instance. */ public void queryAAIForVolumeGroup(DelegateExecution execution, isDebugLogEnabled) { def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId') def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion') AaiUtil aaiUtil = new AaiUtil(this) String aaiEndpoint = aaiUtil.getCloudInfrastructureCloudRegionEndpoint(execution) String queryAAIVolumeGroupRequest = aaiEndpoint + '/' + URLEncoder.encode(aicCloudRegion, "UTF-8") + "/volume-groups/volume-group/" + UriUtils.encode(volumeGroupId, "UTF-8") msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest) msoLogger.debug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest) APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIVolumeGroupRequest) String returnCode = response.getStatusCode() String aaiResponseAsString = response.getResponseBodyAsString() msoLogger.debug("AAI query volume group by id return code: " + returnCode) msoLogger.debug("AAI query volume group by id response: " + aaiResponseAsString) msoLogger.debug("AAI Volume Group return code: " + returnCode) msoLogger.debug("AAI Volume Group response: " + aaiResponseAsString) ExceptionUtil exceptionUtil = new ExceptionUtil() if ((returnCode == '200') || (returnCode == '204')) { execution.setVariable('UPDVfModVol_aaiVolumeGroupResponse', aaiResponseAsString) //def heatStackId = getNodeTextForce(aaiResponseAsString, 'heat-stack-id') //execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', heatStackId) def volumeGroupTenantId = getTenantIdFromVolumeGroup(aaiResponseAsString) if (volumeGroupTenantId == null) { exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id " + volumeGroupId + ", AIC Cloud Region " + aicCloudRegion) } execution.setVariable('UPDVfModVol_volumeGroupTenantId', volumeGroupTenantId) msoLogger.debug("Received Tenant Id " + volumeGroupTenantId + " from AAI for Volume Group with Volume Group Id " + volumeGroupId + ", AIC Cloud Region " + aicCloudRegion) def relatedVfModuleLink = getRelatedVfModuleRelatedLink(aaiResponseAsString) msoLogger.debug("Related VF Module link: " + relatedVfModuleLink) execution.setVariable('UPDVfModVol_relatedVfModuleLink', relatedVfModuleLink) } else if (returnCode == '404') { exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group " + volumeGroupId + " not found at AAI") } else { WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution) throw new BpmnError("MSOWorkflowException") } } /** * Query AAI service instance * @param execution * @param isDebugEnabled */ public void queryAAIForGenericVnf(DelegateExecution execution, isDebugEnabled) { def vnfId = execution.getVariable('vnfId') AaiUtil aaiUtil = new AaiUtil(this) String aaiEndpoint = aaiUtil.getNetworkGenericVnfEndpoint(execution) def String queryAAIRequest = aaiEndpoint + "/" + UriUtils.encode(vnfId, "UTF-8") msoLogger.debug("AAI query generic vnf request: " + queryAAIRequest) APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIRequest) String returnCode = response.getStatusCode() String aaiResponseAsString = response.getResponseBodyAsString() msoLogger.debug("AAI query generic vnf return code: " + returnCode) msoLogger.debug("AAI query generic vnf response: " + aaiResponseAsString) ExceptionUtil exceptionUtil = new ExceptionUtil() if (returnCode=='200') { msoLogger.debug('Generic vnf ' + vnfId + ' found in AAI.') execution.setVariable('UPDVfModVol_AAIQueryGenericVfnResponse', aaiResponseAsString) } else { if (returnCode=='404') { def message = 'Generic vnf ' + vnfId + ' was not found in AAI. Return code: 404.' msoLogger.debug(message) exceptionUtil.buildAndThrowWorkflowException(execution, 2500, message) } else { WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution) throw new BpmnError("MSOWorkflowException") } } } /** * Query AAI for VF Module using vf-module-id * @param execution * @param isDebugLogEnabled */ public void queryAAIForVfModule(DelegateExecution execution, isDebugLogEnabled) { AaiUtil aaiUtil = new AaiUtil(this) String queryAAIVfModuleRequest = execution.getVariable('UPDVfModVol_relatedVfModuleLink') execution.setVariable('UPDVfModVol_personaModelId', '') msoLogger.debug('Query AAI VF Module: ' + queryAAIVfModuleRequest) msoLogger.debug('Query AAI VF Module: ' + queryAAIVfModuleRequest) def aaiUrl = UrnPropertiesReader.getVariable("aai.endpoint", execution) msoLogger.debug('A&AI URL: ' + aaiUrl) def requestEndpoint = aaiUrl + queryAAIVfModuleRequest msoLogger.debug('A&AI request endpoint: ' + requestEndpoint) APIResponse response = aaiUtil.executeAAIGetCall(execution, requestEndpoint) String returnCode = response.getStatusCode() String aaiResponseAsString = response.getResponseBodyAsString() msoLogger.debug("AAI query vf-module: " + returnCode) msoLogger.debug("AAI query vf-module response: " + aaiResponseAsString) msoLogger.debug("AAI query vf-module:: " + returnCode) msoLogger.debug("AAI query vf-module response: " + aaiResponseAsString) ExceptionUtil exceptionUtil = new ExceptionUtil() if ((returnCode == '200') || (returnCode == '204')) { def personaModelId = utils.getNodeText(aaiResponseAsString, 'model-invariant-id') if(personaModelId == null) { //check old attribute name personaModelId = utils.getNodeText(aaiResponseAsString, 'persona-model-id') } msoLogger.debug("vfModule personaModelId: " + personaModelId) execution.setVariable('UPDVfModVol_personaModelId', personaModelId) } else if (returnCode == '404') { exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "VF Module not found at AAI") } else { WorkflowException aWorkflowException = exceptionUtil.MapAAIExceptionToWorkflowException(aaiResponseAsString, execution) throw new BpmnError("MSOWorkflowException") } } /** * */ public String getRelatedVfModuleRelatedLink(xml) { def list = new XmlSlurper().parseText(xml) def vfModuleRelationship = list.'**'.find { node -> node.'related-to'.text() == 'vf-module' } return vfModuleRelationship?.'related-link'?.text() ?: '' } /** * Prepare a Request for invoking the VnfAdapterRest subflow to do * a Volume Group update. * * @param execution The flow's execution instance. */ public void prepVnfAdapterRest(DelegateExecution execution, isDebugLogEnabled) { def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion') def tenantId = execution.getVariable('UPDVfModVol_tenantId') def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId') def aaiVolumeGroupResponse = execution.getVariable('UPDVfModVol_aaiVolumeGroupResponse') def volumeGroupHeatStackId = getNodeTextForce(aaiVolumeGroupResponse, 'heat-stack-id') def volumeGroupName = getNodeTextForce(aaiVolumeGroupResponse, 'volume-group-name') def modelCustomizationId = getNodeTextForce(aaiVolumeGroupResponse, 'vf-module-model-customization-id') if(modelCustomizationId == null) { // Check old attribute name modelCustomizationId = getNodeTextForce(aaiVolumeGroupResponse, 'vf-module-persona-model-customization-id') } def vnfType = execution.getVariable('UPDVfModVol_vnfType') def vnfVersion = execution.getVariable('UPDVfModVol_vnfVersion') def aaiGenericVnfResponse = execution.getVariable('UPDVfModVol_AAIQueryGenericVfnResponse') def vnfId = utils.getNodeText(aaiGenericVnfResponse, 'vnf-id') def vnfName = utils.getNodeText(aaiGenericVnfResponse, 'vnf-name') def volumeParamsXml = execution.getVariable('UPDVfModVol_volumeParams') def volumeGroupParams = transformVolumeParamsToEntries(volumeParamsXml) def requestId = execution.getVariable('UPDVfModVol_requestId') def serviceId = execution.getVariable('UPDVfModVol_serviceId') def messageId = execution.getVariable('mso-request-id') + '-' + System.currentTimeMillis() def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId) def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host",execution) if ('true'.equals(useQualifiedHostName)) { notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl) } String vnfAdapterRestRequest = """ ${MsoUtils.xmlEscape(aicCloudRegion)} ${MsoUtils.xmlEscape(tenantId)} ${MsoUtils.xmlEscape(vnfId)} ${MsoUtils.xmlEscape(vnfName)} ${MsoUtils.xmlEscape(volumeGroupId)} ${MsoUtils.xmlEscape(volumeGroupName)} ${MsoUtils.xmlEscape(volumeGroupHeatStackId)} ${MsoUtils.xmlEscape(vnfType)} ${MsoUtils.xmlEscape(vnfVersion)} ${MsoUtils.xmlEscape(modelCustomizationId)} vnf_id ${MsoUtils.xmlEscape(vnfId)} vnf_name ${MsoUtils.xmlEscape(vnfName)} vf_module_id ${MsoUtils.xmlEscape(volumeGroupId)} vf_module_name ${MsoUtils.xmlEscape(volumeGroupName)} ${volumeGroupParams} true ${MsoUtils.xmlEscape(requestId)} ${MsoUtils.xmlEscape(serviceId)} ${MsoUtils.xmlEscape(messageId)} ${MsoUtils.xmlEscape(notificationUrl)} """ vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest) execution.setVariable('UPDVfModVol_vnfAdapterRestRequest', vnfAdapterRestRequest) msoLogger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest) } /** * Prepare a Request for updating the DB for this Infra request. * * @param execution The flow's execution instance. */ public void prepDbInfraDbRequest(DelegateExecution execution, isDebugLogEnabled) { def requestId = execution.getVariable('UPDVfModVol_requestId') ExceptionUtil exceptionUtil = new ExceptionUtil(); String updateInfraRequest = """ ${MsoUtils.xmlEscape(requestId)} BPEL COMPLETE 100 """ updateInfraRequest = utils.formatXml(updateInfraRequest) execution.setVariable('UPDVfModVol_updateInfraRequest', updateInfraRequest) msoLogger.debug('Request for Update Infra Request:\n' + updateInfraRequest) } /** * Build a "CompletionHandler" request. * @param execution The flow's execution instance. */ public void prepCompletionHandlerRequest(DelegateExecution execution, requestId, action, source, isDebugLogEnabled) { String content = """ ${MsoUtils.xmlEscape(requestId)} UPDATE ${MsoUtils.xmlEscape(source)} BPMN VF Module Volume action: UPDATE """ content = utils.formatXml(content) msoLogger.debug('Request for Completion Handler:\n' + content) execution.setVariable('UPDVfModVol_CompletionHandlerRequest', content) } /** * Build a "FalloutHandler" request. * @param execution The flow's execution instance. */ public void prepFalloutHandler(DelegateExecution execution, isDebugLogEnabled) { def requestId = execution.getVariable('UPDVfModVol_requestId') def source = execution.getVariable('UPDVfModVol_source') String requestInfo = """ ${MsoUtils.xmlEscape(requestId)} UPDATE ${MsoUtils.xmlEscape(source)} """ def WorkflowException workflowException = execution.getVariable("WorkflowException") def errorResponseCode = workflowException.getErrorCode() def errorResponseMsg = workflowException.getErrorMessage() def encErrorResponseMsg = "" if (errorResponseMsg != null) { encErrorResponseMsg = errorResponseMsg } String content = """ ${requestInfo} ${MsoUtils.xmlEscape(encErrorResponseMsg)} ${MsoUtils.xmlEscape(errorResponseCode)} """ content = utils.formatXml(content) msoLogger.debug('Request for Fallout Handler:\n' + content) execution.setVariable('UPDVfModVol_FalloutHandlerRequest', content) } /** * Create a WorkflowException for the error case where the Tenant Id from * AAI did not match the Tenant Id in the incoming request. * @param execution The flow's execution instance. */ public void handleTenantIdMismatch(DelegateExecution execution, isDebugLogEnabled) { def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId') def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion') def tenantId = execution.getVariable('UPDVfModVol_tenantId') def volumeGroupTenantId = execution.getVariable('UPDVfModVol_volumeGroupTenantId') def String errorMessage = "TenantId " + tenantId + " in incoming request does not match Tenant Id " + volumeGroupTenantId + " retrieved from AAI for Volume Group Id " + volumeGroupId + ", AIC Cloud Region " + aicCloudRegion ExceptionUtil exceptionUtil = new ExceptionUtil() msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Error in UpdateVfModuleVol: ' + errorMessage, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception"); exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage) } /** * Create a WorkflowException for the error case where the Personal Model Id from * AAI did not match the model invariant ID in the incoming request. * @param execution The flow's execution instance. */ public void handlePersonaModelIdMismatch(DelegateExecution execution, isDebugLogEnabled) { def modelInvariantId = execution.getVariable('UPDVfModVol_modelInvariantId') def personaModelId = execution.getVariable('UPDVfModVol_personaModelId') def String errorMessage = "Model Invariant ID " + modelInvariantId + " in incoming request does not match persona model ID " + personaModelId + " retrieved from AAI for Volume Group Id " ExceptionUtil exceptionUtil = new ExceptionUtil() msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Error in UpdateVfModuleVol: ' + errorMessage, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception"); exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage) } }