/*-
* ============LICENSE_START=======================================================
* ONAP - SO
* ================================================================================
* Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
* ================================================================================
* Modifications Copyright (c) 2019 Samsung
* ================================================================================
* 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 groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.apache.commons.lang3.StringUtils
import org.camunda.bpm.engine.delegate.BpmnError
import org.camunda.bpm.engine.delegate.DelegateExecution
import org.json.JSONArray
import org.json.JSONObject
import org.onap.so.bpmn.common.scripts.AbstractServiceTaskProcessor
import org.onap.so.bpmn.common.scripts.ExceptionUtil
import org.onap.so.bpmn.common.scripts.MsoUtils
import org.onap.so.bpmn.core.UrnPropertiesReader
import org.onap.so.bpmn.core.WorkflowException
import org.onap.so.bpmn.core.domain.Resource
import org.onap.so.bpmn.core.domain.ServiceDecomposition
import org.onap.so.bpmn.core.json.JsonUtils
import org.onap.so.client.HttpClient
import org.onap.so.client.HttpClientFactory
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.onap.so.utils.TargetEntity
import org.springframework.web.util.UriUtils
import org.w3c.dom.Document
import org.w3c.dom.Node
import org.xml.sax.InputSource
import javax.ws.rs.core.Response
import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory
import static org.apache.commons.lang3.StringUtils.isBlank
/**
* This groovy class supports the DoDeleteE2EServiceInstance.bpmn process.
*
* Inputs:
* @param - msoRequestId
* @param - globalSubscriberId - O
* @param - subscriptionServiceType - O
* @param - serviceInstanceId
* @param - serviceInstanceName - O
* @param - serviceInputParams (should contain aic_zone for serviceTypes TRANSPORT,ATM)
* @param - sdncVersion
* @param - failNotFound - TODO
* @param - serviceInputParams - TODO
*
* @param - delResourceList
* @param - serviceRelationShip
*
* Outputs:
* @param - WorkflowException
*
* Rollback - Deferred
*/
public class DoDeleteE2EServiceInstance extends AbstractServiceTaskProcessor {
String Prefix="DDEESI_"
ExceptionUtil exceptionUtil = new ExceptionUtil()
JsonUtils jsonUtil = new JsonUtils()
private static final Logger logger = LoggerFactory.getLogger( DoDeleteE2EServiceInstance.class);
public void preProcessRequest (DelegateExecution execution) {
logger.debug(" ***** preProcessRequest *****")
String msg = ""
try {
String requestId = execution.getVariable("msoRequestId")
execution.setVariable("prefix",Prefix)
//Inputs
//requestDetails.subscriberInfo. for AAI GET & PUT & SDNC assignToplology
String globalSubscriberId = execution.getVariable("globalSubscriberId") //globalCustomerId
if (globalSubscriberId == null)
{
execution.setVariable("globalSubscriberId", "")
}
//requestDetails.requestParameters. for AAI PUT & SDNC assignTopology
String serviceType = execution.getVariable("serviceType")
if (serviceType == null)
{
execution.setVariable("serviceType", "")
}
//Generated in parent for AAI PUT
String serviceInstanceId = execution.getVariable("serviceInstanceId")
if (isBlank(serviceInstanceId)){
msg = "Input serviceInstanceId is null"
logger.info(msg)
exceptionUtil.buildAndThrowWorkflowException(execution, 500, msg)
}
String sdncCallbackUrl = UrnPropertiesReader.getVariable('URN_mso_workflow_sdncadapter_callback', execution)
if (isBlank(sdncCallbackUrl)) {
msg = "URN_mso_workflow_sdncadapter_callback is null"
logger.info(msg)
exceptionUtil.buildAndThrowWorkflowException(execution, 500, msg)
}
execution.setVariable("sdncCallbackUrl", sdncCallbackUrl)
logger.info("SDNC Callback URL: " + sdncCallbackUrl)
StringBuilder sbParams = new StringBuilder()
Map paramsMap = execution.getVariable("serviceInputParams")
if (paramsMap != null) {
sbParams.append("")
for (Map.Entry entry : paramsMap.entrySet()) {
String paramsXml
String paramName = entry.getKey()
String paramValue = entry.getValue()
paramsXml =
"""
${MsoUtils.xmlEscape(paramName)}
${MsoUtils.xmlEscape(paramValue)}
"""
sbParams.append(paramsXml)
}
sbParams.append("")
}
String siParamsXml = sbParams.toString()
if (siParamsXml == null)
siParamsXml = ""
execution.setVariable("siParamsXml", siParamsXml)
} catch (BpmnError e) {
throw e;
} catch (Exception ex){
msg = "Exception in preProcessRequest " + ex.getMessage()
logger.error(msg)
exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg)
}
logger.debug("***** Exit preProcessRequest *****")
}
public void postProcessAAIGET(DelegateExecution execution) {
logger.debug(" ***** postProcessAAIGET ***** ")
String msg = ""
try {
String serviceInstanceId = execution.getVariable("serviceInstanceId")
boolean foundInAAI = execution.getVariable("GENGS_FoundIndicator")
String serviceType = ""
if(foundInAAI){
logger.debug("Found Service-instance in AAI")
String siData = execution.getVariable("GENGS_service")
logger.debug("SI Data")
if (isBlank(siData))
{
msg = "Could not retrive ServiceInstance data from AAI to delete id:" + serviceInstanceId
logger.error(msg)
exceptionUtil.buildAndThrowWorkflowException(execution, 500, msg)
}
else
{
InputSource source = new InputSource(new StringReader(siData));
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder()
Document serviceXml = docBuilder.parse(source)
serviceXml.getDocumentElement().normalize()
// get model invariant id
// Get Template uuid and version
if (utils.nodeExists(siData, "model-invariant-id") && utils.nodeExists(siData, "model-version-id") ) {
logger.debug("SI Data model-invariant-id and model-version-id exist")
def modelInvariantId = serviceXml.getElementsByTagName("model-invariant-id").item(0).getTextContent()
def modelVersionId = serviceXml.getElementsByTagName("model-version-id").item(0).getTextContent()
// Set Original Template info
execution.setVariable("model-invariant-id-original", modelInvariantId)
execution.setVariable("model-version-id-original", modelVersionId)
}
logger.debug("SI Data" + siData)
//Confirm there are no related service instances (vnf/network or volume)
if (utils.nodeExists(siData, "relationship-list")) {
logger.debug("SI Data relationship-list exists")
JSONArray jArray = new JSONArray()
XmlParser xmlParser = new XmlParser()
Node root = xmlParser.parseText(siData)
def relation_list = utils.getChildNode(root, 'relationship-list')
def relationships = utils.getIdenticalChildren(relation_list, 'relationship')
for (def relation: relationships) {
def jObj = getRelationShipData(relation, isDebugEnabled)
jArray.put(jObj)
}
execution.setVariable("serviceRelationShip", jArray.toString())
execution.setVariable("serviceRelationShip", jArray.toString())
}
}
}else{
boolean succInAAI = execution.getVariable("GENGS_SuccessIndicator")
if(!succInAAI){
logger.debug("Error getting Service-instance from AAI :" + serviceInstanceId)
WorkflowException workflowException = execution.getVariable("WorkflowException")
if(workflowException != null){
logger.error("workflowException: " + workflowException)
exceptionUtil.buildAndThrowWorkflowException(execution, workflowException.getErrorCode(), workflowException.getErrorMessage())
}
else {
msg = "Failure in postProcessAAIGET GENGS_SuccessIndicator:" + succInAAI
logger.error(msg)
exceptionUtil.buildAndThrowWorkflowException(execution, 2500, msg)
}
}
logger.debug("Service-instance NOT found in AAI. Silent Success")
}
}catch (BpmnError e) {
throw e
} catch (Exception ex) {
msg = "Exception in DoDeleteE2EServiceInstance.postProcessAAIGET. " + ex.getMessage()
logger.debug(msg)
exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg)
}
logger.debug(" *** Exit postProcessAAIGET *** ")
}
private JSONObject getRelationShipData(node, isDebugEnabled){
JSONObject jObj = new JSONObject()
def relation = utils.nodeToString(node)
def rt = utils.getNodeText(relation, "related-to")
def rl = utils.getNodeText(relation, "related-link")
logger.debug("ServiceInstance Related NS/Configuration :" + rl)
def rl_datas = utils.getIdenticalChildren(node, "relationship-data")
for(def rl_data : rl_datas) {
def eKey = utils.getChildNodeText(rl_data, "relationship-key")
def eValue = utils.getChildNodeText(rl_data, "relationship-value")
if ((rt == "service-instance" && eKey.equals("service-instance.service-instance-id"))
//for overlay/underlay
|| (rt == "configuration" && eKey.equals("configuration.configuration-id")
)){
jObj.put("resourceInstanceId", eValue)
}
// for sp-partner and others
else if(eKey.endsWith("-id")){
jObj.put("resourceInstanceId", eValue)
String resourceName = rt + eValue;
jObj.put("resourceType", resourceName)
}
jObj.put("resourceLinkUrl", rl)
}
def rl_props = utils.getIdenticalChildren(node, "related-to-property")
for(def rl_prop : rl_props) {
def eKey = utils.getChildNodeText(rl_prop, "property-key")
def eValue = utils.getChildNodeText(rl_prop, "property-value")
if((rt == "service-instance" && eKey.equals("service-instance.service-instance-name"))
//for overlay/underlay
|| (rt == "configuration" && eKey.equals("configuration.configuration-type"))){
jObj.put("resourceType", eValue)
}
}
logger.debug("Relationship related to Resource:" + jObj.toString())
return jObj
}
public void getCurrentNS(DelegateExecution execution){
logger.info( "======== Start getCurrentNS Process ======== ")
def currentIndex = execution.getVariable("currentNSIndex")
List nsSequence = execution.getVariable("nsSequence")
String nsResourceType = nsSequence.get(currentIndex)
// GET AAI by Name, not ID, for process convenient
execution.setVariable("GENGS_type", "service-instance")
execution.setVariable("GENGS_serviceInstanceId", "")
execution.setVariable("GENGS_serviceInstanceName", nsResourceType)
logger.debug("======== COMPLETED getCurrentNS Process ======== ")
}
public void prepareDecomposeService(DelegateExecution execution) {
try {
logger.debug(" ***** Inside prepareDecomposeService of create generic e2e service ***** ")
String modelInvariantUuid = execution.getVariable("model-invariant-id-original")
String modelVersionId = execution.getVariable("model-version-id-original")
String serviceModelInfo = """{
"modelInvariantUuid":"${modelInvariantUuid}",
"modelUuid":"${modelVersionId}",
"modelVersion":""
}"""
execution.setVariable("serviceModelInfo", serviceModelInfo)
logger.debug(" ***** Completed prepareDecomposeService of create generic e2e service ***** ")
} catch (Exception ex) {
// try error in method block
String exceptionMessage = "Bpmn error encountered in create generic e2e service flow. Unexpected Error from method prepareDecomposeService() - " + ex.getMessage()
logger.error(exceptionMessage)
exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
}
}
private void generateRelatedResourceInfo(String response, JSONObject jObj){
def xml = new XmlSlurper().parseText(response)
def rtn = xml.childNodes()
while (rtn.hasNext()) {
groovy.util.slurpersupport.Node node = rtn.next()
def key = node.name()
def value = node.text()
jObj.put(key, value)
}
}
private JSONObject getRelatedResourceInAAI (DelegateExecution execution, JSONObject jObj)
{
logger.debug(" ***** Started getRelatedResourceInAAI *****")
String aai_endpoint = UrnPropertiesReader.getVariable("aai.endpoint", execution)
String urlLink = jObj.get("resourceLinkUrl")
String serviceAaiPath = "${aai_endpoint}${urlLink}"
URL url = new URL(serviceAaiPath)
HttpClient client = new HttpClientFactory().newXmlClient(url, TargetEntity.AAI)
Response response = client.get()
int responseCode = response.getStatus()
execution.setVariable(Prefix + "GeRelatedResourceResponseCode", responseCode)
logger.debug(" Get RelatedResource code is: " + responseCode)
String aaiResponse = response.readEntity(String.class)
execution.setVariable(Prefix + "GetRelatedResourceResponse", aaiResponse)
//Process Response
if(responseCode == 200 || responseCode == 201 || responseCode == 202 )
//200 OK 201 CREATED 202 ACCEPTED
{
logger.debug("GET RelatedResource Received a Good Response")
execution.setVariable(Prefix + "SuccessIndicator", true)
execution.setVariable(Prefix + "FoundIndicator", true)
generateRelatedResourceInfo(aaiResponse, jObj)
//get model-invariant-uuid and model-uuid
String modelInvariantId = ""
String modelUuid = ""
String modelCustomizationId = ""
if(jObj.has("model-invariant-id")) {
modelInvariantId = jObj.get("model-invariant-id")
modelUuid = jObj.get("model-version-id")
modelCustomizationId = jObj.get("model-customization-id")
}
jObj.put("modelInvariantId", modelInvariantId)
jObj.put("modelVersionId", modelUuid)
jObj.put("modelCustomizationId", modelCustomizationId)
}
else {
String exceptionMessage = "Get RelatedResource Received a Bad Response Code. Response Code is: " + responseCode
logger.error(exceptionMessage)
exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
}
logger.debug(" ***** Exit getRelatedResourceInAAI *****")
return jObj
}
public void postDecomposeService(DelegateExecution execution) {
logger.debug(" ***** Inside processDecomposition() of delete generic e2e service flow ***** ")
try {
ServiceDecomposition serviceDecomposition = execution.getVariable("serviceDecomposition")
// service model info
execution.setVariable("serviceModelInfo", serviceDecomposition.getModelInfo())
List deleteResourceList = serviceDecomposition.getServiceResources()
String serviceRelationShip = execution.getVariable("serviceRelationShip")
def jsonSlurper = new JsonSlurper()
def jsonOutput = new JsonOutput()
List relationShipList = null
if (serviceRelationShip != null) {
relationShipList = jsonSlurper.parseText(serviceRelationShip)
}
List deleteRealResourceList = new ArrayList()
//Set the real resource instance id to the decomosed resource list
//reset the resource instance id , because in the decompose flow ,its a random one.
//match the resource-instance-name and the model name
if (relationShipList != null) {
relationShipList.each {
JSONObject obj = getRelatedResourceInAAI(execution, (JSONObject)it)
for (Resource resource : deleteResourceList) {
String modelName = resource.getModelInfo().getModelName()
String modelCustomizationUuid = resource.getModelInfo().getModelCustomizationUuid()
if (StringUtils.containsIgnoreCase(obj.get("resourceType"), modelName)) {
resource.setResourceId(obj.get("resourceInstanceId"))
deleteRealResourceList.add(resource)
}
else if (modelCustomizationUuid.equals(obj.get("modelCustomizationId"))) {
resource.setResourceId(obj.get("resourceInstanceId"))
resource.setResourceInstanceName(obj.get("resourceType"))
deleteRealResourceList.add(resource)
}
}
}
}
// only delete real existing resources
execution.setVariable("deleteResourceList", deleteRealResourceList)
boolean isDeleteResourceListValid = false
if(deleteRealResourceList.size() > 0) {
isDeleteResourceListValid = true
}
execution.setVariable("isDeleteResourceListValid", isDeleteResourceListValid)
logger.debug("delete resource list : " + deleteRealResourceList)
} catch (Exception ex) {
String exceptionMessage = "Bpmn error encountered in create generic e2e service flow. processDecomposition() - " + ex.getMessage()
logger.error(exceptionMessage)
exceptionUtil.buildAndThrowWorkflowException(execution, 7000, exceptionMessage)
}
logger.debug( " ***** exit processDecomposition() of delete generic e2e service flow ***** ")
}
public void preInitResourcesOperStatus(DelegateExecution execution){
logger.debug(" ======== STARTED preInitResourcesOperStatus Process ======== ")
try{
String serviceId = execution.getVariable("serviceInstanceId")
String operationId = execution.getVariable("operationId")
String operationType = execution.getVariable("operationType")
String resourceTemplateUUIDs = ""
String result = "processing"
String progress = "0"
String reason = ""
String operationContent = "Prepare service creation"
logger.debug("Generated new operation for Service Instance serviceId:" + serviceId + " operationId:" + operationId + " operationType:" + operationType)
serviceId = UriUtils.encode(serviceId,"UTF-8")
execution.setVariable("serviceInstanceId", serviceId)
execution.setVariable("operationId", operationId)
execution.setVariable("operationType", operationType)
List deleteResourceList = execution.getVariable("deleteResourceList")
String serviceRelationShip = execution.getVariable("serviceRelationShip")
for(Resource resource : deleteResourceList){
resourceTemplateUUIDs = resourceTemplateUUIDs + resource.getModelInfo().getModelCustomizationUuid() + ":"
}
def dbAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.openecomp.db.endpoint", execution)
execution.setVariable("URN_mso_adapters_openecomp_db_endpoint", dbAdapterEndpoint)
String payload =
"""
${MsoUtils.xmlEscape(serviceId)}
${MsoUtils.xmlEscape(operationId)}
${MsoUtils.xmlEscape(operationType)}
${MsoUtils.xmlEscape(resourceTemplateUUIDs)}
"""
payload = utils.formatXml(payload)
execution.setVariable("CVFMI_initResOperStatusRequest", payload)
logger.debug("Outgoing initResourceOperationStatus: \n" + payload)
logger.debug("CreateVfModuleInfra Outgoing initResourceOperationStatus Request: " + payload)
}catch(Exception e){
logger.debug("Exception Occured Processing preInitResourcesOperStatus. Exception is:\n" + e)
execution.setVariable("CVFMI_ErrorResponse", "Error Occurred during preInitResourcesOperStatus Method:\n" + e.getMessage())
}
logger.debug("======== COMPLETED preInitResourcesOperStatus Process ======== ")
}
public void prepareUpdateServiceOperationStatus(DelegateExecution execution){
logger.debug(" ======== STARTED prepareUpdateServiceOperationStatus Process ======== ")
try{
String serviceId = execution.getVariable("serviceInstanceId")
String operationId = execution.getVariable("operationId")
String userId = ""
String result = execution.getVariable("result")
String progress = execution.getVariable("progress")
String reason = ""
String operationContent = execution.getVariable("operationContent")
serviceId = UriUtils.encode(serviceId,"UTF-8")
def dbAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.openecomp.db.endpoint", execution)
execution.setVariable("CVFMI_dbAdapterEndpoint", dbAdapterEndpoint)
logger.debug("DB Adapter Endpoint is: " + dbAdapterEndpoint)
String payload =
"""
${MsoUtils.xmlEscape(serviceId)}
${MsoUtils.xmlEscape(operationId)}
DELETE
${MsoUtils.xmlEscape(userId)}
${MsoUtils.xmlEscape(result)}
${MsoUtils.xmlEscape(operationContent)}
${MsoUtils.xmlEscape(reason)}
"""
payload = utils.formatXml(payload)
execution.setVariable("CVFMI_updateServiceOperStatusRequest", payload)
logger.debug("Outgoing updateServiceOperStatusRequest: \n" + payload)
}catch(Exception e){
logger.error("Exception Occured Processing prepareUpdateServiceOperationStatus. Exception is:\n" + e)
execution.setVariable("CVFMI_ErrorResponse", "Error Occurred during prepareUpdateServiceOperationStatus Method:\n" + e.getMessage())
}
logger.debug("======== COMPLETED prepareUpdateServiceOperationStatus Process ======== ")
}
/**
* post config request.
*/
public void postConfigRequest(execution){
//to do
}
}