/*- * ============LICENSE_START======================================================= * OPENECOMP - MSO * ================================================================================ * 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.openecomp.mso.bpmn.infrastructure.scripts import groovy.json.JsonSlurper import java.util.concurrent.ExecutionException; import org.camunda.bpm.engine.delegate.BpmnError import org.camunda.bpm.engine.runtime.Execution import org.apache.commons.lang3.* import org.springframework.web.util.UriUtils import org.openecomp.mso.bpmn.common.scripts.AaiUtil; import org.openecomp.mso.bpmn.common.scripts.ExceptionUtil; import org.openecomp.mso.bpmn.common.scripts.VfModuleBase; import org.openecomp.mso.bpmn.common.scripts.VidUtils; import org.openecomp.mso.bpmn.core.WorkflowException import org.openecomp.mso.rest.APIResponse import org.openecomp.mso.rest.RESTClient import org.openecomp.mso.rest.RESTConfig class UpdateVfModuleVolumeInfraV1 extends VfModuleBase { /** * Initialize the flow's variables. * * @param execution The flow's execution instance. */ private void initProcessVariables(Execution 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 (Execution execution) { def isDebugEnabled=execution.getVariable("isDebugLogEnabled") preProcessRequest(execution, isDebugEnabled) } public void preProcessRequest(Execution 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.modelInvariantId ?: '' execution.setVariable('UPDVfModVol_modelInvariantId', modelInvariantId) utils.log("DEBUG", "XML request:\n" + request, isDebugLogEnabled) } catch(groovy.json.JsonException je) { utils.log("DEBUG", " Request is in XML format.", isDebugLogEnabled) // 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', getRequiredNodeText(execution, 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')) try { // Catalog DB headers Authorization String basicAuthValueDB = execution.getVariable("URN_mso_adapters_db_auth") utils.log("DEBUG", " Obtained BasicAuth userid password for Catalog DB adapter: " + basicAuthValueDB, isDebugLogEnabled) def encodedString = utils.getBasicAuth(basicAuthValueDB, execution.getVariable("URN_mso_msoKey")) execution.setVariable("BasicAuthHeaderValueDB",encodedString) } catch (IOException ex) { String dataErrorMessage = " Unable to encode Catalog DB user/password string - " + ex.getMessage() utils.log("DEBUG", dataErrorMessage, isDebugLogEnabled) exceptionUtil.buildAndThrowWorkflowException(execution, 2500, dataErrorMessage) } 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(Execution 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 = """ ${requestId} UPDATE_VF_MODULE_VOL IN_PROGRESS ${progress} ${startTime} ${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) } logDebug('Sync response: ' + syncResponse, isDebugLogEnabled) 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(Execution 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") utils.logAudit('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest) logDebug('Query AAI volume group by ID: ' + queryAAIVolumeGroupRequest, isDebugLogEnabled) APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIVolumeGroupRequest) String returnCode = response.getStatusCode() String aaiResponseAsString = response.getResponseBodyAsString() aaiResponseAsString = StringEscapeUtils.unescapeXml(aaiResponseAsString) utils.logAudit("AAI query volume group by id return code: " + returnCode) utils.logAudit("AAI query volume group by id response: " + aaiResponseAsString) logDebug("AAI Volume Group return code: " + returnCode, isDebugLogEnabled) logDebug("AAI Volume Group response: " + aaiResponseAsString, isDebugLogEnabled) 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) logDebug("Received Tenant Id " + volumeGroupTenantId + " from AAI for Volume Group with Volume Group Id " + volumeGroupId + ", AIC Cloud Region " + aicCloudRegion, isDebugLogEnabled) def relatedVfModuleLink = getRelatedVfModuleRelatedLink(aaiResponseAsString) logDebug("Related VF Module link: " + relatedVfModuleLink, isDebugLogEnabled) 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(Execution 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") utils.logAudit("AAI query generic vnf request: " + queryAAIRequest) APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIRequest) String returnCode = response.getStatusCode() String aaiResponseAsString = response.getResponseBodyAsString() aaiResponseAsString = StringEscapeUtils.unescapeXml(aaiResponseAsString) utils.logAudit("AAI query generic vnf return code: " + returnCode) utils.logAudit("AAI query generic vnf response: " + aaiResponseAsString) ExceptionUtil exceptionUtil = new ExceptionUtil() if (returnCode=='200') { utils.log("DEBUG", 'Generic vnf ' + vnfId + ' found in AAI.', isDebugEnabled) execution.setVariable('UPDVfModVol_AAIQueryGenericVfnResponse', aaiResponseAsString) } else { if (returnCode=='404') { def message = 'Generic vnf ' + vnfId + ' was not found in AAI. Return code: 404.' utils.log("DEBUG", message, isDebugEnabled) 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(Execution execution, isDebugLogEnabled) { AaiUtil aaiUtil = new AaiUtil(this) String queryAAIVfModuleRequest = execution.getVariable('UPDVfModVol_relatedVfModuleLink') execution.setVariable('UPDVfModVol_personaModelId', '') utils.logAudit('Query AAI VF Module: ' + queryAAIVfModuleRequest) logDebug('Query AAI VF Module: ' + queryAAIVfModuleRequest, isDebugLogEnabled) APIResponse response = aaiUtil.executeAAIGetCall(execution, queryAAIVfModuleRequest) String returnCode = response.getStatusCode() String aaiResponseAsString = response.getResponseBodyAsString() aaiResponseAsString = StringEscapeUtils.unescapeXml(aaiResponseAsString) utils.logAudit("AAI query vf-module: " + returnCode) utils.logAudit("AAI query vf-module response: " + aaiResponseAsString) logDebug("AAI query vf-module:: " + returnCode, isDebugLogEnabled) logDebug("AAI query vf-module response: " + aaiResponseAsString, isDebugLogEnabled) ExceptionUtil exceptionUtil = new ExceptionUtil() if ((returnCode == '200') || (returnCode == '204')) { def personaModelId = utils.getNodeText1(aaiResponseAsString, 'persona-model-id') 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(Execution 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-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.getNodeText1(aaiGenericVnfResponse, 'vnf-id') def vnfName = utils.getNodeText1(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 = execution.getVariable("URN_mso_use_qualified_host") if ('true'.equals(useQualifiedHostName)) { notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl) } String vnfAdapterRestRequest = """ ${aicCloudRegion} ${tenantId} ${vnfId} ${vnfName} ${volumeGroupId} ${volumeGroupName} ${volumeGroupHeatStackId} ${vnfType} ${vnfVersion} ${modelCustomizationId} vnf_id ${vnfId} vnf_name ${vnfName} vf_module_id ${volumeGroupId} vf_module_name ${volumeGroupName} ${volumeGroupParams} true ${requestId} ${serviceId} ${messageId} ${notificationUrl} """ vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest) execution.setVariable('UPDVfModVol_vnfAdapterRestRequest', vnfAdapterRestRequest) logDebug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest, isDebugLogEnabled) } /** * Prepare a Request for updating the DB for this Infra request. * * @param execution The flow's execution instance. */ public void prepDbInfraDbRequest(Execution execution, isDebugLogEnabled) { def requestId = execution.getVariable('UPDVfModVol_requestId') String updateInfraRequest = """ ${requestId} BPEL COMPLETE 100 """ updateInfraRequest = utils.formatXml(updateInfraRequest) execution.setVariable('UPDVfModVol_updateInfraRequest', updateInfraRequest) logDebug('Request for Update Infra Request:\n' + updateInfraRequest, isDebugLogEnabled) } /** * Build a "CompletionHandler" request. * @param execution The flow's execution instance. */ public void prepCompletionHandlerRequest(Execution execution, requestId, action, source, isDebugLogEnabled) { String content = """ ${requestId} CREATE ${source} BPMN VF Module Volume action: UPDATE """ content = utils.formatXml(content) logDebug('Request for Completion Handler:\n' + content, isDebugLogEnabled) execution.setVariable('UPDVfModVol_CompletionHandlerRequest', content) } /** * Build a "FalloutHandler" request. * @param execution The flow's execution instance. */ public void prepFalloutHandler(Execution execution, isDebugLogEnabled) { def requestInfo = execution.getVariable('UPDVfModVol_requestInfo') def WorkflowException workflowException = execution.getVariable("WorkflowException") def errorResponseCode = workflowException.getErrorCode() def errorResponseMsg = workflowException.getErrorMessage() def encErrorResponseMsg = "" if (errorResponseMsg != null) { encErrorResponseMsg = errorResponseMsg.replace("&", "&").replace("<", "<").replace(">", ">") } String content = """ ${requestInfo} ${encErrorResponseMsg} ${errorResponseCode} """ content = utils.formatXml(content) logDebug('Request for Fallout Handler:\n' + content, isDebugLogEnabled) 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(Execution 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() logError('Error in UpdateVfModuleVol: ' + errorMessage) 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(Execution 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() logError('Error in UpdateVfModuleVol: ' + errorMessage) exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage) } }