diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js index d5896c05..b17bb387 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js @@ -181,18 +181,18 @@ export async function bindUsingPush(csar, serviceTaskId, elementRegistry) { async function extractSelfserviceApplicationUrl(propertiesUrl) { let buildPlanResponse = await fetchDataFromEndpoint(propertiesUrl); console.log(buildPlanResponse); - const selfserviceApplicationUrl = buildPlanResponse.outputs.filter( - (x) => x.name === "selfserviceApplicationUrl" + const selfServiceApplicationUrl = buildPlanResponse.outputs.filter( + (x) => x.name === "selfServiceApplicationUrl" ); if ( - selfserviceApplicationUrl === undefined || - selfserviceApplicationUrl.length < 1 + selfServiceApplicationUrl === undefined || + selfServiceApplicationUrl.length < 1 ) { console.error( - "Unable to fetch selfserviceApplicationUrl from: " + propertiesUrl + "Unable to fetch selfServiceApplicationUrl from: " + propertiesUrl ); return undefined; } - console.log(selfserviceApplicationUrl); - return selfserviceApplicationUrl[0].value; + console.log(selfServiceApplicationUrl); + return selfServiceApplicationUrl[0].value; } diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js b/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js index 65f743bd..2c7cdc91 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js @@ -14,13 +14,14 @@ import { getXml } from "../../../editor/util/IoUtilities"; import * as config from "../framework-config/config-manager"; import { makeId } from "../deployment/OpenTOSCAUtils"; import { getCamundaEndpoint } from "../../../editor/config/EditorConfigManager"; -import { createElement } from "../../../editor/util/camunda-utils/ElementUtil"; import { - getCamundaInputOutput, - getRootProcess, -} from "../../../editor/util/ModellingUtilities"; + createElement, + createLayoutedShape, +} from "../../../editor/util/camunda-utils/ElementUtil"; +import { getCamundaInputOutput } from "../../../editor/util/ModellingUtilities"; import { layout } from "../../quantme/replacement/layouter/Layouter"; import { deletePolicies } from "../utilities/Utilities"; +import { getQProvEndpoint } from "../../quantme/framework-config/config-manager"; const fetchMethod = ` function fetch(method, url, body) { @@ -59,6 +60,7 @@ function fetch(method, url, body) { } }`; +// TODO make request that checks if csar is already uploading before trying upload otherwise can lead to conflicts function createDeploymentScript( opentoscaEndpoint, camundaEndpoint, @@ -66,7 +68,8 @@ function createDeploymentScript( subprocessId, inputParams, taskId, - reconstructedVMs + reconstructedVMs, + QProvEndpoint ) { return ` var inputParams = ${JSON.stringify(inputParams)}; @@ -77,7 +80,7 @@ ${fetchMethod} var createCsarResponse = fetch('POST', "${opentoscaEndpoint}", JSON.stringify({ enrich: 'false', - name: urlParts[urlParts.length - 1] + ".csar", + name: urlParts[urlParts.length - 2] + ".csar", url: execution.getVariable("completeModelUrl_" + "${taskId}") + "?csar" })) @@ -97,7 +100,7 @@ for (const [key, value] of Object.entries(deployedTopology.nodeTemplates)) { } java.lang.System.out.println("Input parameters after update: " + JSON.stringify(inputParams)); -var serviceTemplates = JSON.parse(fetch('GET', "${opentoscaEndpoint}" + "/" + urlParts[urlParts.length - 1] ".csar/servicetemplates")) +var serviceTemplates = JSON.parse(fetch('GET', "${opentoscaEndpoint}" + "/" + urlParts[urlParts.length - 2] + ".csar/servicetemplates")) var buildPlansUrl = serviceTemplates.service_templates[0]._links.self.href + '/buildplans' var buildPlans = JSON.parse(fetch('GET', buildPlansUrl)) var buildPlanUrl = buildPlans.plans[0]._links.self.href @@ -107,13 +110,18 @@ for(var i = 0; i < inputParameters.length; i++) { inputParameters[i].value = "${camundaEndpoint}" } else if(inputParameters[i].name === "camundaTopic") { inputParameters[i].value = "${camundaTopic}" + } else if(inputParameters[i].name === "QProvEndpoint") { + inputParameters[i].value = "${QProvEndpoint}" } else { inputParameters[i].value = inputParams[inputParameters[i].name]; } } +java.lang.System.out.println("Creating instance using URL: " + buildPlanUrl + "/instances"); var createInstanceResponse = fetch('POST', buildPlanUrl + "/instances", JSON.stringify(inputParameters)) -execution.setVariable("${subprocessId}" + "_deploymentBuildPlanInstanceUrl", buildPlanUrl + "/instances/" + createInstanceResponse);`; +execution.setVariable("${subprocessId}" + "_deploymentBuildPlanInstanceUrl", buildPlanUrl + "/instances/" + createInstanceResponse); +java.lang.System.out.println("Build plan URL: " + buildPlanUrl + "/instances/" + createInstanceResponse); +`; } function createWaitScript(subprocessId, taskId) { @@ -133,14 +141,12 @@ for(var i = 0; i < 20; i++) { console.log("InstanceUrl: " + instanceUrl); -var buildPlanUrl = ""; for(var i = 0; i < 50; i++) { try { java.lang.System.out.println("Iteration: " + i); var createInstanceResponse = fetch('GET', instanceUrl); var instance = JSON.parse(createInstanceResponse); console.log("Instance state: " + instance.state); - buildPlanUrl = instance._links.build_plan_instance.href; if (instance && instance.state === "CREATED") { break; } @@ -150,15 +156,17 @@ for(var i = 0; i < 50; i++) { java.lang.Thread.sleep(30000); } -console.log("Retrieving selfServiceApplicationUrl from build plan output from URL: ", buildPlanUrl); -var buildPlanResult = JSON.parse(fetch('GET', buildPlanUrl)); -console.log("Build plan result: ", buildPlanResult); -var buildPlanOutputs = buildPlanResult.outputs; -console.log("Outputs: ", buildPlanOutputs.toString()); -var selfserviceApplicationUrl = buildPlanOutputs.filter((output) => output.name === "selfserviceApplicationUrl"); -console.log("SelfServiceApplicationUrl: " + selfserviceApplicationUrl[0].value); - -execution.setVariable("${taskId}" + "_selfserviceApplicationUrl", selfserviceApplicationUrl[0].value); +var serviceTemplateInstanceUrl = instanceUrl + "/properties"; +console.log("Retrieving selfServiceApplicationUrl from service instance url: ", serviceTemplateInstanceUrl); +var serviceTemplateInstanceUrlResult = JSON.parse(fetch('GET', serviceTemplateInstanceUrl)); +var selfServiceApplicationUrl = serviceTemplateInstanceUrlResult.selfServiceApplicationUrl; +console.log("Retrieved selfServiceApplicationUrl: " + selfServiceApplicationUrl); +execution.setVariable("${taskId}" + "_selfServiceApplicationUrl", selfServiceApplicationUrl); + +var qProvUrl = serviceTemplateInstanceUrlResult.qProvUrl; +console.log("Retrieved qProvUrl: " + qProvUrl); +execution.setVariable("${taskId}" + "_qProvUrl", qProvUrl); + java.lang.Thread.sleep(12000); `; } @@ -171,7 +179,7 @@ def blacklist = ${JSON.stringify(blacklist)}; def slurper = new JsonSlurper(); def policies = slurper.parseText(${JSON.stringify(policies)}); -def message = JsonOutput.toJson("policies": policies, "blacklist": blacklist); +def message = JsonOutput.toJson("policies": policies, "blacklistedNodetypes": blacklist); try { def post = new URL(url).openConnection(); @@ -297,7 +305,7 @@ try { } println "Found instance with state CREATED. Extracting selfServiceUrl..."; - def instancesLink = serviceTemplateInstance.get("_links").get("self").get("href"); + def instancesLink = serviceTemplateInstance.get("_links").get("self").get("href") + "/properties"; println "Retrieving instance information from URL: " + instancesLink; get = new URL(instancesLink).openConnection(); @@ -312,33 +320,17 @@ try { resultText = get.getInputStream().getText(); json = new JsonSlurper().parseText(resultText); - def buildPlanLink = json .get("_links").get("build_plan_instance").get("href"); - println "Retrieved build plan URL: " + buildPlanLink; - - get = new URL(buildPlanLink).openConnection(); - get.setRequestMethod("GET"); - get.setDoOutput(true); - get.setRequestProperty("accept", "application/json"); - status = get.getResponseCode(); - if(status != 200){ - println "Unable to retrieve build plan information. Skipping..."; - continue; - } - - resultText = get.getInputStream().getText(); - json = new JsonSlurper().parseText(resultText); - def outputs = json.get("outputs"); - println outputs; + + def selfServiceApplicationUrl = json.get("selfServiceApplicationUrl"); - def selfserviceApplicationUrlEntry = outputs.findAll { it.name.equalsIgnoreCase("selfserviceApplicationUrl") }; - if(selfserviceApplicationUrlEntry .size() < 1) { - println "Unable to retrieve selfserviceApplicationUrl. Skipping..."; - continue; - } - def selfserviceApplicationUrl = selfserviceApplicationUrlEntry[0].value; - println "Retrieved selfserviceApplicationUrl: " + selfserviceApplicationUrl; + println "Retrieved selfServiceApplicationUrl: " + selfServiceApplicationUrl; execution.setVariable("instanceAvailable", "true"); - execution.setVariable("${taskId}" + "_selfserviceApplicationUrl", selfserviceApplicationUrl); + execution.setVariable("${taskId}" + "_selfServiceApplicationUrl", selfServiceApplicationUrl); + + def qProvUrl = json.get("qProvUrl"); + println "Retrieved qProvUrl: " + qProvUrl; + execution.setVariable("${taskId}" + "_qProvUrl", qProvUrl); + return; } } @@ -368,8 +360,6 @@ export async function startOnDemandReplacementProcess(xml, csars) { const bpmnAutoResizeProvider = modeler.get("bpmnAutoResizeProvider"); const bpmnFactory = modeler.get("bpmnFactory"); bpmnAutoResizeProvider.canResize = () => false; - const definitions = modeler.getDefinitions(); - const rootElement = getRootProcess(definitions); let serviceTaskIds = []; csars @@ -392,7 +382,7 @@ export async function startOnDemandReplacementProcess(xml, csars) { deletePolicies(modeler, serviceTaskId); let CSARForServiceTask = csars.filter((csar) => - csar.serviceTaskIds.filter((id) => id === serviceTaskId) + csar.serviceTaskIds.includes(serviceTaskId) )[0]; let onDemand = serviceTask.businessObject.get("onDemand"); if (onDemand) { @@ -416,21 +406,23 @@ export async function startOnDemandReplacementProcess(xml, csars) { deploymentModelUrl ); - const startEvent = modeling.createShape( + const startEvent = createLayoutedShape( + modeling, { type: "bpmn:StartEvent", }, - { x: 200, y: 200 }, + { x: subProcess.x + 30, y: subProcess.y + 30 }, subProcess ); - const serviceTaskCompleteDeploymentModel = modeling.appendShape( - startEvent, - { - type: "bpmn:ScriptTask", - }, - { x: 400, y: 200 } + const serviceTaskCompleteDeploymentModel = createLayoutedShape( + modeling, + { type: "bpmn:ScriptTask" }, + { x: 50, y: 50 }, + subProcess, + {} ); + serviceTaskCompleteDeploymentModel.businessObject.set( "name", "Adapt Model" @@ -451,8 +443,13 @@ export async function startOnDemandReplacementProcess(xml, csars) { ) ); + modeling.connect(startEvent, serviceTaskCompleteDeploymentModel, { + type: "bpmn:SequenceFlow", + }); + // add gateway to check for dedicated policy - let dedicatedGateway = modeling.createShape( + let dedicatedGateway = createLayoutedShape( + modeling, { type: "bpmn:ExclusiveGateway" }, { x: 50, y: 50 }, subProcess, @@ -467,7 +464,8 @@ export async function startOnDemandReplacementProcess(xml, csars) { }); // add task to check for running container instance - let serviceTaskCheckForEquivalentDeploymentModel = modeling.createShape( + let serviceTaskCheckForEquivalentDeploymentModel = createLayoutedShape( + modeling, { type: "bpmn:ScriptTask" }, { x: 50, y: 50 }, subProcess, @@ -499,11 +497,13 @@ export async function startOnDemandReplacementProcess(xml, csars) { dedicatedFlowBo.name = "no"; let dedicatedFlowCondition = bpmnFactory.create("bpmn:FormalExpression"); dedicatedFlowCondition.body = - '${execution.hasVariable("dedicatedHosting") == false || dedicatedHosting == false}'; + '${(execution.hasVariable("dedicatedHosting") == false || dedicatedHosting == false) ||' + + ` (execution.hasVariable("${serviceTask.id}" + "_selfServiceApplicationUrl") == true )}`; dedicatedFlowBo.conditionExpression = dedicatedFlowCondition; // add task to check for available instance - let serviceTaskCheckForAvailableInstance = modeling.createShape( + let serviceTaskCheckForAvailableInstance = createLayoutedShape( + modeling, { type: "bpmn:ScriptTask" }, { x: 50, y: 50 }, subProcess, @@ -536,7 +536,8 @@ export async function startOnDemandReplacementProcess(xml, csars) { ); // add gateway to check if instance is available - let instanceAvailablityGateway = modeling.createShape( + let instanceAvailablityGateway = createLayoutedShape( + modeling, { type: "bpmn:ExclusiveGateway" }, { x: 50, y: 50 }, subProcess, @@ -555,7 +556,8 @@ export async function startOnDemandReplacementProcess(xml, csars) { } ); - let joiningDedicatedGateway = modeling.createShape( + let joiningDedicatedGateway = createLayoutedShape( + modeling, { type: "bpmn:ExclusiveGateway" }, { x: 50, y: 50 }, subProcess, @@ -597,11 +599,13 @@ export async function startOnDemandReplacementProcess(xml, csars) { "bpmn:FormalExpression" ); notDedicatedFlowCondition.body = - '${execution.hasVariable("dedicatedHosting") == true && dedicatedHosting == true}'; + '${(execution.hasVariable("dedicatedHosting") == true && dedicatedHosting == true) &&' + + ` (execution.hasVariable("${serviceTask.id}" + "_selfServiceApplicationUrl") == false )}`; notDedicatedFlowBo.conditionExpression = notDedicatedFlowCondition; let topicName = makeId(12); - const scriptTaskUploadToContainer = modeling.createShape( + const scriptTaskUploadToContainer = createLayoutedShape( + modeling, { type: "bpmn:ScriptTask" }, { x: 50, y: 50 }, subProcess, @@ -622,7 +626,8 @@ export async function startOnDemandReplacementProcess(xml, csars) { subProcess.id, CSARForServiceTask.inputParams, serviceTask.id, - CSARForServiceTask.reconstructedVMs + CSARForServiceTask.reconstructedVMs, + getQProvEndpoint() ) ); scriptTaskUploadToContainer.businessObject.set( @@ -634,7 +639,8 @@ export async function startOnDemandReplacementProcess(xml, csars) { type: "bpmn:SequenceFlow", }); - const scriptTaskWaitForDeployment = modeling.createShape( + const scriptTaskWaitForDeployment = createLayoutedShape( + modeling, { type: "bpmn:ScriptTask" }, { x: 50, y: 50 }, subProcess, @@ -659,7 +665,8 @@ export async function startOnDemandReplacementProcess(xml, csars) { } ); - let joiningInstanceAvailablityGatewayGateway = modeling.createShape( + let joiningInstanceAvailablityGatewayGateway = createLayoutedShape( + modeling, { type: "bpmn:ExclusiveGateway" }, { x: 50, y: 50 }, subProcess, @@ -693,12 +700,20 @@ export async function startOnDemandReplacementProcess(xml, csars) { InstanceAvailableFlowBo.conditionExpression = InstanceAvailableFlowCondition; - const serviceTaskInvokeService = modeling.createShape( + const serviceTaskInvokeService = createLayoutedShape( + modeling, { type: "bpmn:ServiceTask" }, { x: 50, y: 50 }, subProcess, {} ); + modeling.connect( + joiningInstanceAvailablityGatewayGateway, + serviceTaskInvokeService, + { + type: "bpmn:SequenceFlow", + } + ); const extensionElements = serviceTask.businessObject.extensionElements; serviceTaskInvokeService.businessObject.set("name", "Invoke Service"); if (!extensionElements) { @@ -714,7 +729,7 @@ export async function startOnDemandReplacementProcess(xml, csars) { if (param.name === "url") { param.value = `\${${ serviceTask.id - }_selfserviceApplicationUrl.concat(${JSON.stringify( + }_selfServiceApplicationUrl.concat(${JSON.stringify( param.value || "" )})}`; break; @@ -722,14 +737,6 @@ export async function startOnDemandReplacementProcess(xml, csars) { } } - modeling.connect( - joiningInstanceAvailablityGatewayGateway, - serviceTaskInvokeService, - { - type: "bpmn:SequenceFlow", - } - ); - const newExtensionElements = createElement( "bpmn:ExtensionElements", { values }, @@ -756,7 +763,8 @@ export async function startOnDemandReplacementProcess(xml, csars) { newExtensionElements ); } - let endEvent = modeling.createShape( + let endEvent = createLayoutedShape( + modeling, { type: "bpmn:EndEvent" }, { x: 50, y: 50 }, subProcess, @@ -766,11 +774,13 @@ export async function startOnDemandReplacementProcess(xml, csars) { type: "bpmn:SequenceFlow", }); - layout(modeling, elementRegistry, rootElement); + // expand subprocess, layout, and collapse again + subProcess.di.isExpanded = true; + layout(modeling, elementRegistry, subProcess.businessObject); + subProcess.di.isExpanded = false; } } - // layout diagram after successful transformation let updatedXml = await getXml(modeler); console.log(updatedXml);