From 50999c4f1cf57335fed4eb1292274831b014b13e Mon Sep 17 00:00:00 2001 From: mklkun Date: Fri, 12 Nov 2021 17:41:45 +0100 Subject: [PATCH 1/2] Fix image id for OpenStack VM acquiring and refactoring --- .../org/activeeon/morphemic/PAGateway.java | 482 +-------------- .../{service => nc}/NodeCandidateUtils.java | 4 +- .../UpdatingNodeCandidatesThread.java | 2 +- .../morphemic/service/TaskBuilder.java | 561 ++++++++++++++++++ 4 files changed, 572 insertions(+), 477 deletions(-) rename scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/{service => nc}/NodeCandidateUtils.java (99%) rename scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/{service => nc}/UpdatingNodeCandidatesThread.java (94%) create mode 100644 scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java index 552d4699..9c2ffb5a 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java @@ -1,6 +1,8 @@ package org.activeeon.morphemic; import com.fasterxml.jackson.databind.ObjectMapper; +import org.activeeon.morphemic.nc.NodeCandidateUtils; +import org.activeeon.morphemic.nc.UpdatingNodeCandidatesThread; import org.apache.commons.lang3.tuple.Pair; import lombok.extern.slf4j.Slf4j; import org.activeeon.morphemic.application.deployment.PAFactory; @@ -49,11 +51,7 @@ public class PAGateway { public final PAConnectorIaasGateway connectorIaasGateway; - private static final String NEW_LINE = System.getProperty("line.separator"); - - private static final String SCRIPTS_SEPARATION_BASH = NEW_LINE + NEW_LINE + "# Main script" + NEW_LINE + NEW_LINE; - - private static final String SCRIPTS_SEPARATION_GROOVY = NEW_LINE + NEW_LINE + "// Separation script" + NEW_LINE + NEW_LINE; + public final TaskBuilder taskBuilder = new TaskBuilder(); /** * Construct a gateway to the ProActive server @@ -288,6 +286,7 @@ public class PAGateway { environment.setEnvironmentVars(vars); newTask.setEnvironment(environment); LOGGER.info("vars calculated" + vars); + break; case "commands": CommandsInstallation commands = new CommandsInstallation(); commands.setPreInstall(installation.optString("preInstall")); @@ -1057,209 +1056,6 @@ public class PAGateway { return 0; } - private List createAppTasks(Task task, String taskNameSuffix, String taskToken, Job job) { - switch (task.getType()) { - case "commands": - return createCommandsTask(task, taskNameSuffix, taskToken, job); - case "docker": - return createDockerTask(task, taskNameSuffix, taskToken); - } - - return new LinkedList<>(); - } - - private List createDockerTask(Task task, String taskNameSuffix, String taskToken) { - List scriptTasks = new LinkedList<>(); - ScriptTask scriptTask = PAFactory.createBashScriptTaskFromFile(task.getName() + taskNameSuffix, "start_docker_app.sh"); - Map taskVariablesMap = new HashMap<>(); - taskVariablesMap.put("INSTANCE_NAME", new TaskVariable("INSTANCE_NAME", task.getTaskId() + "-$PA_JOB_ID")); - taskVariablesMap.put("DOCKER_IMAGE", new TaskVariable("DOCKER_IMAGE", task.getEnvironment().getDockerImage())); - taskVariablesMap.put("PORTS", new TaskVariable("PORTS", task.getEnvironment().getPort())); - taskVariablesMap.put("ENV_VARS", new TaskVariable("ENV_VARS", task.getEnvironment().getEnvVarsAsCommandString())); - scriptTask.setVariables(taskVariablesMap); - scriptTask.addGenericInformation("NODE_ACCESS_TOKEN", taskToken); - scriptTasks.add(scriptTask); - return scriptTasks; - } - - private List createCommandsTask(Task task, String taskNameSuffix, String taskToken, Job job) { - List scriptTasks = new LinkedList<>(); - ScriptTask scriptTaskStart = null; - ScriptTask scriptTaskInstall = null; - - Map taskVariablesMap = new HashMap<>(); - if (!task.getParentTasks().isEmpty()) { - //TODO: Taking into consideration multiple parent tasks with multiple communications - taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", - job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); - } - - if (!(task.getInstallation().getInstall().isEmpty() && - task.getInstallation().getPreInstall().isEmpty() && - task.getInstallation().getPostInstall().isEmpty())) { - if (!task.getInstallation().getInstall().isEmpty()) { - scriptTaskInstall = PAFactory.createBashScriptTask(task.getName() + "_install" + taskNameSuffix, - Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + - task.getInstallation().getInstall()); - } else { - scriptTaskInstall = PAFactory.createBashScriptTask(task.getName() + "_install" + taskNameSuffix, - "echo \"Installation script is empty. Nothing to be executed.\""); - } - - if (!task.getInstallation().getPreInstall().isEmpty()) { - scriptTaskInstall.setPreScript(PAFactory.createSimpleScript( - Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + - task.getInstallation().getPreInstall(), - "bash")); - } - if (!task.getInstallation().getPostInstall().isEmpty()) { - scriptTaskInstall.setPostScript(PAFactory.createSimpleScript( - Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + - task.getInstallation().getPostInstall(), - "bash")); - } - if (!task.getParentTasks().isEmpty()) { - scriptTaskInstall.setVariables(taskVariablesMap); - } - scriptTaskInstall.addGenericInformation("NODE_ACCESS_TOKEN", taskToken); - scriptTasks.add(scriptTaskInstall); - } - - if (!(task.getInstallation().getStart().isEmpty() && - task.getInstallation().getPreStart().isEmpty() && - task.getInstallation().getPostStart().isEmpty())) { - if (!task.getInstallation().getStart().isEmpty()) { - scriptTaskStart = PAFactory.createBashScriptTask(task.getName() + "_start" + taskNameSuffix, - Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + - task.getInstallation().getStart()); - } else { - scriptTaskStart = PAFactory.createBashScriptTask(task.getName() + "_start" + taskNameSuffix, - "echo \"Installation script is empty. Nothing to be executed.\""); - } - - if (!task.getInstallation().getPreStart().isEmpty()) { - scriptTaskStart.setPreScript(PAFactory.createSimpleScript( - Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + - task.getInstallation().getPreStart(), - "bash")); - } - if (!task.getInstallation().getPostStart().isEmpty()) { - scriptTaskStart.setPostScript(PAFactory.createSimpleScript( - Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + - task.getInstallation().getPostStart(), - "bash")); - } - if (!task.getParentTasks().isEmpty()) { - scriptTaskStart.setVariables(taskVariablesMap); - } - if(scriptTaskInstall != null) { - scriptTaskStart.addDependence(scriptTaskInstall); - } - scriptTaskStart.addGenericInformation("NODE_ACCESS_TOKEN", taskToken); - scriptTasks.add(scriptTaskStart); - } - return scriptTasks; - } - - private ScriptTask createInfraTask(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { - switch (deployment.getDeploymentType()) { - case IAAS: - return createInfraIAASTask(task, deployment, taskNameSuffix, nodeToken); - case BYON: - return createInfraBYONTask(task, deployment, taskNameSuffix, nodeToken); - } - - return new ScriptTask(); - } - - private ScriptTask createInfraIAASTask(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { - LOGGER.debug("Acquiring node AWS script file: " + getClass().getResource(File.separator + "acquire_node_aws_script.groovy").toString()); - ScriptTask deployNodeTask = PAFactory.createGroovyScriptTaskFromFile("acquireAWSNode_" + task.getName() + taskNameSuffix, - "acquire_node_aws_script.groovy"); - - deployNodeTask.setPreScript(PAFactory.createSimpleScriptFromFIle("pre_acquire_node_script.groovy", "groovy")); - - Map variablesMap = new HashMap<>(); - variablesMap.put("NS_name", new TaskVariable("NS_name", - deployment.getPaCloud().getNodeSourceNamePrefix() + deployment.getLocationName())); - variablesMap.put("nVMs", new TaskVariable("nVMs", "1", "PA:Integer", false)); - variablesMap.put("synchronous", new TaskVariable("synchronous", "true", "PA:Boolean", false)); - variablesMap.put("timeout", new TaskVariable("timeout", "700", "PA:Long", false)); - ObjectMapper mapper = new ObjectMapper(); - String nodeConfigJson = "{\"image\": \"" + deployment.getLocationName() + "/" + deployment.getImageProviderId() + "\", " + - "\"vmType\": \"" + deployment.getHardwareProviderId() + "\", " + - "\"nodeTags\": \"" + deployment.getNodeName(); - if (task.getPortsToOpen() == null || task.getPortsToOpen().isEmpty()) { - nodeConfigJson += "\"}"; - } else { - try { - nodeConfigJson += "\", \"portsToOpen\": " + mapper.writeValueAsString(task.getPortsToOpen()) + "}"; - } catch (IOException e) { - LOGGER.error(Arrays.toString(e.getStackTrace())); - } - } - variablesMap.put("nodeConfigJson", new TaskVariable("nodeConfigJson", nodeConfigJson, "PA:JSON", false)); - variablesMap.put("token", new TaskVariable("token", nodeToken)); - LOGGER.debug("Variables to be added to the task: " + variablesMap.toString()); - deployNodeTask.setVariables(variablesMap); - - addLocalDefaultNSRegexSelectionScript(deployNodeTask); - - return deployNodeTask; - } - - private ScriptTask createInfraBYONTask(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { - LOGGER.debug("Acquiring node BYON script file: " + getClass().getResource(File.separator + "acquire_node_BYON_script.groovy").toString()); - ScriptTask deployNodeTask = PAFactory.createGroovyScriptTaskFromFile("acquireBYONNode_" + task.getName() + taskNameSuffix, - "acquire_node_BYON_script.groovy"); - - deployNodeTask.setPreScript(PAFactory.createSimpleScriptFromFIle("pre_acquire_node_script.groovy", "groovy")); - - Map variablesMap = new HashMap<>(); - variablesMap.put("NS_name", new TaskVariable("NS_name", - deployment.getPaCloud().getNodeSourceNamePrefix() + deployment.getLocationName())); - //TODO: To check this. Which ip address is used as host in RM? - variablesMap.put("host_name", new TaskVariable("host_name", - deployment.getByonNode().getIpAddresses().get(0).getValue())); - variablesMap.put("token", new TaskVariable("token", nodeToken)); - - LOGGER.debug("Variables to be added to the task: " + variablesMap.toString()); - deployNodeTask.setVariables(variablesMap); - - addLocalDefaultNSRegexSelectionScript(deployNodeTask); - - return deployNodeTask; - } - - private void addLocalDefaultNSRegexSelectionScript(ScriptTask scriptTask) { - try { - String selectionScriptFileName = "check_node_source_regexp.groovy"; - String[] nodeSourceNameRegex = {"^local$|^Default$"}; - SelectionScript selectionScript = new SelectionScript(Utils.getContentWithFileName(selectionScriptFileName), - "groovy", - nodeSourceNameRegex, - true); - scriptTask.setSelectionScript(selectionScript); - } catch (InvalidScriptException e) { - LOGGER.warn("Selection script could not have been added."); - } - } - - private ScriptTask createEmsDeploymentTask(EmsDeploymentRequest emsDeploymentRequest, String taskNameSuffix, String nodeToken) { - LOGGER.debug("Preparing EMS deployment task"); - ScriptTask emsDeploymentTask = PAFactory.createComplexScriptTaskFromFiles("emsDeployment" + taskNameSuffix, - "emsdeploy_mainscript.groovy", - "groovy", - "emsdeploy_prescript.sh", - "bash", - "emsdeploy_postscript.sh", - "bash"); - Map variablesMap = emsDeploymentRequest.getWorkflowMap(); - emsDeploymentTask.addGenericInformation("NODE_ACCESS_TOKEN", nodeToken); - emsDeploymentTask.setVariables(variablesMap); - return emsDeploymentTask; - } - /** * Register a set of node as an operation for scale up * @param nodeNames Name of the nodes to be created and provisioned @@ -1354,7 +1150,7 @@ public class PAGateway { EntityManagerHelper.begin(); job.getTasks().forEach(task -> { - List scriptTasks = buildScalingOutPATask(task, job, scaledTaskName); + List scriptTasks = taskBuilder.buildScalingOutPATask(task, job, scaledTaskName); if (scriptTasks != null && !scriptTasks.isEmpty()) { addAllScriptTasksToPAJob(paJob, task, scriptTasks); @@ -1426,154 +1222,6 @@ public class PAGateway { }); } - private List buildScalingOutPATask(Task task, Job job, String scaledTaskName) { - List scriptTasks = new LinkedList<>(); - Task scaledTask = job.findTask(scaledTaskName); - - if (scaledTask.getParentTasks().contains(task.getName())) { - // When the scaled task is a child the task to be built - LOGGER.info("Building task " + task.getName() + " as a parent of task " + scaledTaskName); - scriptTasks.addAll(createParentScaledTask(task, job)); - } else { - // Using buildScalingInPATask because it handles all the remaining cases - LOGGER.info("Moving to building with buildScalingInPATask() method"); - scriptTasks.addAll(buildScalingInPATask(task, job, scaledTaskName)); - } - - return scriptTasks; - } - - private List createChildScaledTask(Task task, Job job) { - List scriptTasks = new LinkedList<>(); - task.getDeployments().stream().filter(Deployment::getIsDeployed).forEach(deployment -> { - // Creating infra deployment tasks - String token = task.getTaskId() + deployment.getNumber(); - String suffix = "_" + deployment.getNumber(); - scriptTasks.add(createScalingChildUpdateTask(task, suffix, token, job)); - }); - task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); - task.setDeploymentLastSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); - return scriptTasks; - } - - private ScriptTask createScalingChildUpdateTask(Task task, String suffix, String token, Job job) { - ScriptTask scriptTaskUpdate = null; - - Map taskVariablesMap = new HashMap<>(); - //TODO: Taking into consideration multiple parent tasks with multiple communications - taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", - job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); - - if (!task.getInstallation().getUpdateCmd().isEmpty()) { - scriptTaskUpdate = PAFactory.createBashScriptTask(task.getName() + "_update" + suffix, - Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + - task.getInstallation().getUpdateCmd()); - } else { - scriptTaskUpdate = PAFactory.createBashScriptTask(task.getName() + "_install" + suffix, - "echo \"Installation script is empty. Nothing to be executed.\""); - } - - scriptTaskUpdate.setPreScript(PAFactory.createSimpleScriptFromFIle("collect_ip_addr_results.groovy", - "groovy")); - - scriptTaskUpdate.setVariables(taskVariablesMap); - scriptTaskUpdate.addGenericInformation("NODE_ACCESS_TOKEN", token); - - return scriptTaskUpdate; - } - - private List buildScaledPATask(Task task, Job job) { - List scriptTasks = new LinkedList<>(); - - task.getDeployments().stream().filter(Deployment::getIsDeployed).forEach(deployment -> { - String token = task.getTaskId() + deployment.getNumber(); - String suffix = "_" + deployment.getNumber(); - - // Creating infra preparation task - scriptTasks.add(createInfraPreparationTask(task, suffix, token, job)); - }); - - task.setDeploymentLastSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); - task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); - - task.getDeployments().stream().filter(deployment -> !deployment.getIsDeployed()).forEach(deployment -> { - // Creating infra deployment tasks - String token = task.getTaskId() + deployment.getNumber(); - String suffix = "_" + deployment.getNumber(); - scriptTasks.add(createInfraTask(task, deployment, suffix, token)); - task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(scriptTasks.size()-1).getName().substring(0, scriptTasks.get(scriptTasks.size()-1).getName().lastIndexOf("_"))); - // If the infrastructure comes with the deployment of the EMS, we set it up. - Optional.ofNullable(deployment.getEmsDeployment()).ifPresent(emsDeploymentRequest -> { - String emsTaskSuffix = "_" + task.getName() + suffix; - ScriptTask emsScriptTask = createEmsDeploymentTask(emsDeploymentRequest,emsTaskSuffix,token); - emsScriptTask.addDependence(scriptTasks.get(scriptTasks.size()-1)); - scriptTasks.add(emsScriptTask); - }); - LOGGER.info("Token added: " + token); - deployment.setIsDeployed(true); - deployment.setNodeAccessToken(token); - - // Creating application deployment tasks - createAndAddAppDeploymentTasks(task, suffix, token, scriptTasks, job); - }); - - scriptTasks.forEach(scriptTask -> task.addSubmittedTaskName(scriptTask.getName())); - - return scriptTasks; - } - - private void createAndAddAppDeploymentTasks(Task task, String suffix, String token, List scriptTasks, Job job) { - List appTasks = createAppTasks(task, suffix, token, job); - task.setDeploymentLastSubmittedTaskName(appTasks.get(appTasks.size()-1).getName().substring(0, appTasks.get(appTasks.size()-1).getName().lastIndexOf(suffix))); - - // Creating infra preparation task - appTasks.add(0, createInfraPreparationTask(task, suffix, token, job)); - appTasks.get(1).addDependence(appTasks.get(0)); - - // Add dependency between infra and application deployment tasks - appTasks.get(0).addDependence(scriptTasks.get(scriptTasks.size()-1)); - - scriptTasks.addAll(appTasks); - } - - private List createParentScaledTask(Task task, Job job) { - List scriptTasks = new LinkedList<>(); - task.getDeployments().stream().filter(Deployment::getIsDeployed).forEach(deployment -> { - // Creating infra deployment tasks - String token = task.getTaskId() + deployment.getNumber(); - String suffix = "_" + deployment.getNumber(); - scriptTasks.add(createScalingParentInfraPreparationTask(task, suffix, token, job)); - }); - task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); - task.setDeploymentLastSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); - return scriptTasks; - } - - private ScriptTask createScalingParentInfraPreparationTask(Task task, String suffix, String token, Job job) { - ScriptTask prepareInfraTask; - Map taskVariablesMap = new HashMap<>(); - String taskName = "parentPrepareInfra_" + task.getName() + suffix; - - if (!task.getPortsToOpen().isEmpty()) { - prepareInfraTask = PAFactory.createGroovyScriptTaskFromFile(taskName, "post_prepare_infra_script.groovy"); - prepareInfraTask.setPreScript(PAFactory.createSimpleScriptFromFIle("prepare_infra_script.sh", - "bash")); - //TODO: Taking into consideration multiple provided ports - taskVariablesMap.put("providedPortName", new TaskVariable("providedPortName", - task.getPortsToOpen().get(0).getRequestedName())); - taskVariablesMap.put("providedPortValue", new TaskVariable("providedPortValue", - task.getPortsToOpen().get(0).getValue().toString())); - } else { - prepareInfraTask = PAFactory.createBashScriptTask(taskName, - "echo \"No ports to open and not parent tasks. Nothing to be prepared in VM.\""); - } - - prepareInfraTask.setVariables(taskVariablesMap); - prepareInfraTask.addGenericInformation("NODE_ACCESS_TOKEN", token); - - return prepareInfraTask; - } - /** * Unregister a set of node as a scale-down operation * @param nodeNames A list of node to be removed @@ -1659,7 +1307,7 @@ public class PAGateway { EntityManagerHelper.begin(); job.getTasks().forEach(task -> { - List scriptTasks = buildScalingInPATask(task, job, scaledTaskName); + List scriptTasks = taskBuilder.buildScalingInPATask(task, job, scaledTaskName); if (scriptTasks != null && !scriptTasks.isEmpty()) { addAllScriptTasksToPAJob(paJob, task, scriptTasks); @@ -1681,122 +1329,6 @@ public class PAGateway { LOGGER.info("Scaling out of task \'" + scaledTaskName + "\' job, submitted successfully. ID = " + submittedJobId); } - private List buildScalingInPATask(Task task, Job job, String scaledTaskName) { - List scriptTasks = new LinkedList<>(); - - if (scaledTaskName.equals(task.getName())) { - // When the scaled task is the task to be built - LOGGER.info("Building task " + task.getName() + " as it is scaled out"); - scriptTasks.addAll(buildScaledPATask(task, job)); - } else if (task.getParentTasks().contains(scaledTaskName)) { - // When the scaled task is a parent of the task to be built - LOGGER.info("Building task " + task.getName() + " as a child of task " + scaledTaskName); - scriptTasks.addAll(createChildScaledTask(task, job)); - } else { - LOGGER.debug("Task " + task.getName() + " is not impacted by the scaling of task " + scaledTaskName); - } - - return scriptTasks; - } - - /** - * Translate a Morphemic task skeleton into a list of ProActive tasks - * @param task A Morphemic task skeleton - * @param job The related job skeleton - * @return A list of ProActive tasks - */ - public List buildPATask(Task task, Job job) { - List scriptTasks = new LinkedList<>(); - - if (task.getDeployments() == null || task.getDeployments().isEmpty()) { - LOGGER.warn("The task " + task.getName() + " does not have a deployment. It will be scheduled on any free node."); - scriptTasks.addAll(createAppTasks(task, "", "", job)); - task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName()); - task.setDeploymentLastSubmittedTaskName(scriptTasks.get(scriptTasks.size()-1).getName()); - } - else { - task.getDeployments().stream().filter(deployment -> !deployment.getIsDeployed()).forEach(deployment -> { - // Creating infra deployment tasks - String token = task.getTaskId() + deployment.getNumber(); - String suffix = "_" + deployment.getNumber(); - scriptTasks.add(createInfraTask(task, deployment, suffix, token)); - // If the infrastructure comes with the deployment of the EMS, we set it up. - Optional.ofNullable(deployment.getEmsDeployment()).ifPresent(emsDeploymentRequest -> { - String emsTaskSuffix = "_" + task.getName() + suffix; - ScriptTask emsScriptTask = createEmsDeploymentTask(emsDeploymentRequest,emsTaskSuffix,token); - emsScriptTask.addDependence(scriptTasks.get(scriptTasks.size()-1)); - scriptTasks.add(emsScriptTask); - }); - LOGGER.info("Token added: " + token); - deployment.setIsDeployed(true); - deployment.setNodeAccessToken(token); - - LOGGER.info("+++ Deployment number: " + deployment.getNumber()); - - - // Creating application deployment tasks - createAndAddAppDeploymentTasks(task, suffix, token, scriptTasks, job); - }); - if(!scriptTasks.isEmpty()) { - task.setDeploymentFirstSubmittedTaskName( - scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); - } - } - - scriptTasks.forEach(scriptTask -> task.addSubmittedTaskName(scriptTask.getName())); - - return scriptTasks; - } - - private ScriptTask createInfraPreparationTask(Task task, String suffix, String token, Job job) { - ScriptTask prepareInfraTask; - Map taskVariablesMap = new HashMap<>(); - String taskName = "prepareInfra_" + task.getName() + suffix; - - if (!task.getPortsToOpen().isEmpty()) { - prepareInfraTask = PAFactory.createBashScriptTaskFromFile(taskName, "prepare_infra_script.sh"); - prepareInfraTask.setPostScript(PAFactory.createSimpleScript( - Utils.getContentWithFileName("post_prepare_infra_script.groovy") - + SCRIPTS_SEPARATION_GROOVY + Utils.getContentWithFileName("collect_ip_addr_results.groovy"), - "groovy")); - //TODO: Taking into consideration multiple provided ports - taskVariablesMap.put("providedPortName", new TaskVariable("providedPortName", - task.getPortsToOpen().get(0).getRequestedName())); - taskVariablesMap.put("providedPortValue", new TaskVariable("providedPortValue", - task.getPortsToOpen().get(0).getValue().toString())); - if (!task.getParentTasks().isEmpty()) { - //TODO: Taking into consideration multiple parent tasks with multiple communications - taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", - job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); - } - } else if (!task.getParentTasks().isEmpty()) { - prepareInfraTask = PAFactory.createBashScriptTaskFromFile(taskName, "prepare_infra_script.sh"); - prepareInfraTask.setPostScript(PAFactory.createSimpleScript( - Utils.getContentWithFileName("collect_ip_addr_results.groovy"), "groovy")); - //TODO: Taking into consideration multiple parent tasks with multiple communications - taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", - job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); - } else { - prepareInfraTask = PAFactory.createBashScriptTask(taskName, - "echo \"No ports to open and not parent tasks. Nothing to be prepared in VM.\""); - } - - if (task.getInstallation().getOperatingSystemType().getOperatingSystemFamily().toLowerCase(Locale.ROOT).equals("ubuntu") && - task.getInstallation().getOperatingSystemType().getOperatingSystemVersion() < 2000) { - LOGGER.info("Adding apt lock handler script since task: " + task.getName() + - " is meant to be executed in: " + - task.getInstallation().getOperatingSystemType().getOperatingSystemFamily() + - " version: " + task.getInstallation().getOperatingSystemType().getOperatingSystemVersion()); - prepareInfraTask.setPreScript(PAFactory.createSimpleScriptFromFIle("wait_for_lock_script.sh", - "bash")); - } - - prepareInfraTask.setVariables(taskVariablesMap); - prepareInfraTask.addGenericInformation("NODE_ACCESS_TOKEN", token); - - return prepareInfraTask; - } - private void setAllMandatoryDependencies(TaskFlowJob paJob, Job jobToSubmit) { jobToSubmit.getTasks().forEach(task -> { if (task.getParentTasks() != null && !task.getParentTasks().isEmpty()) { @@ -1833,7 +1365,7 @@ public class PAGateway { EntityManagerHelper.begin(); jobToSubmit.getTasks().forEach(task -> { - List scriptTasks = buildPATask(task, jobToSubmit); + List scriptTasks = taskBuilder.buildPATask(task, jobToSubmit); addAllScriptTasksToPAJob(paJob, task, scriptTasks); EntityManagerHelper.persist(task); diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/NodeCandidateUtils.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/nc/NodeCandidateUtils.java similarity index 99% rename from scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/NodeCandidateUtils.java rename to scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/nc/NodeCandidateUtils.java index dab5e633..b328697a 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/NodeCandidateUtils.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/nc/NodeCandidateUtils.java @@ -1,9 +1,11 @@ -package org.activeeon.morphemic.service; +package org.activeeon.morphemic.nc; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.activeeon.morphemic.infrastructure.deployment.PAConnectorIaasGateway; import org.activeeon.morphemic.model.*; +import org.activeeon.morphemic.service.EntityManagerHelper; +import org.activeeon.morphemic.service.GeoLocationUtils; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONObject; diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/UpdatingNodeCandidatesThread.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/nc/UpdatingNodeCandidatesThread.java similarity index 94% rename from scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/UpdatingNodeCandidatesThread.java rename to scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/nc/UpdatingNodeCandidatesThread.java index 1e33ebb3..1425a46d 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/UpdatingNodeCandidatesThread.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/nc/UpdatingNodeCandidatesThread.java @@ -1,4 +1,4 @@ -package org.activeeon.morphemic.service; +package org.activeeon.morphemic.nc; import lombok.AllArgsConstructor; import lombok.SneakyThrows; diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java new file mode 100644 index 00000000..f9532ba9 --- /dev/null +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java @@ -0,0 +1,561 @@ +package org.activeeon.morphemic.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.activeeon.morphemic.application.deployment.PAFactory; +import org.activeeon.morphemic.model.Deployment; +import org.activeeon.morphemic.model.EmsDeploymentRequest; +import org.activeeon.morphemic.model.Job; +import org.activeeon.morphemic.model.Task; +import org.ow2.proactive.scheduler.common.task.ScriptTask; +import org.ow2.proactive.scheduler.common.task.TaskVariable; +import org.ow2.proactive.scripting.InvalidScriptException; +import org.ow2.proactive.scripting.SelectionScript; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +@Slf4j +public class TaskBuilder { + + private static final String NEW_LINE = System.getProperty("line.separator"); + + private static final String SCRIPTS_SEPARATION_BASH = NEW_LINE + NEW_LINE + "# Main script" + NEW_LINE + NEW_LINE; + + private static final String SCRIPTS_SEPARATION_GROOVY = NEW_LINE + NEW_LINE + "// Separation script" + NEW_LINE + NEW_LINE; + + private ScriptTask createEmsDeploymentTask(EmsDeploymentRequest emsDeploymentRequest, String taskNameSuffix, String nodeToken) { + LOGGER.debug("Preparing EMS deployment task"); + ScriptTask emsDeploymentTask = PAFactory.createComplexScriptTaskFromFiles("emsDeployment" + taskNameSuffix, + "emsdeploy_mainscript.groovy", + "groovy", + "emsdeploy_prescript.sh", + "bash", + "emsdeploy_postscript.sh", + "bash"); + Map variablesMap = emsDeploymentRequest.getWorkflowMap(); + emsDeploymentTask.addGenericInformation("NODE_ACCESS_TOKEN", nodeToken); + emsDeploymentTask.setVariables(variablesMap); + return emsDeploymentTask; + } + + private List createAppTasks(Task task, String taskNameSuffix, String taskToken, Job job) { + switch (task.getType()) { + case "commands": + return createCommandsTask(task, taskNameSuffix, taskToken, job); + case "docker": + return createDockerTask(task, taskNameSuffix, taskToken); + } + + return new LinkedList<>(); + } + + private List createDockerTask(Task task, String taskNameSuffix, String taskToken) { + List scriptTasks = new LinkedList<>(); + ScriptTask scriptTask = PAFactory.createBashScriptTaskFromFile(task.getName() + taskNameSuffix, "start_docker_app.sh"); + Map taskVariablesMap = new HashMap<>(); + taskVariablesMap.put("INSTANCE_NAME", new TaskVariable("INSTANCE_NAME", task.getTaskId() + "-$PA_JOB_ID")); + taskVariablesMap.put("DOCKER_IMAGE", new TaskVariable("DOCKER_IMAGE", task.getEnvironment().getDockerImage())); + taskVariablesMap.put("PORTS", new TaskVariable("PORTS", task.getEnvironment().getPort())); + taskVariablesMap.put("ENV_VARS", new TaskVariable("ENV_VARS", task.getEnvironment().getEnvVarsAsCommandString())); + scriptTask.setVariables(taskVariablesMap); + scriptTask.addGenericInformation("NODE_ACCESS_TOKEN", taskToken); + scriptTasks.add(scriptTask); + return scriptTasks; + } + + + private List createCommandsTask(Task task, String taskNameSuffix, String taskToken, Job job) { + List scriptTasks = new LinkedList<>(); + ScriptTask scriptTaskStart = null; + ScriptTask scriptTaskInstall = null; + + Map taskVariablesMap = new HashMap<>(); + if (!task.getParentTasks().isEmpty()) { + //TODO: Taking into consideration multiple parent tasks with multiple communications + taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", + job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); + } + + if (!(task.getInstallation().getInstall().isEmpty() && + task.getInstallation().getPreInstall().isEmpty() && + task.getInstallation().getPostInstall().isEmpty())) { + if (!task.getInstallation().getInstall().isEmpty()) { + scriptTaskInstall = PAFactory.createBashScriptTask(task.getName() + "_install" + taskNameSuffix, + Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + + task.getInstallation().getInstall()); + } else { + scriptTaskInstall = PAFactory.createBashScriptTask(task.getName() + "_install" + taskNameSuffix, + "echo \"Installation script is empty. Nothing to be executed.\""); + } + + if (!task.getInstallation().getPreInstall().isEmpty()) { + scriptTaskInstall.setPreScript(PAFactory.createSimpleScript( + Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + + task.getInstallation().getPreInstall(), + "bash")); + } + if (!task.getInstallation().getPostInstall().isEmpty()) { + scriptTaskInstall.setPostScript(PAFactory.createSimpleScript( + Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + + task.getInstallation().getPostInstall(), + "bash")); + } + if (!task.getParentTasks().isEmpty()) { + scriptTaskInstall.setVariables(taskVariablesMap); + } + scriptTaskInstall.addGenericInformation("NODE_ACCESS_TOKEN", taskToken); + scriptTasks.add(scriptTaskInstall); + } + + if (!(task.getInstallation().getStart().isEmpty() && + task.getInstallation().getPreStart().isEmpty() && + task.getInstallation().getPostStart().isEmpty())) { + if (!task.getInstallation().getStart().isEmpty()) { + scriptTaskStart = PAFactory.createBashScriptTask(task.getName() + "_start" + taskNameSuffix, + Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + + task.getInstallation().getStart()); + } else { + scriptTaskStart = PAFactory.createBashScriptTask(task.getName() + "_start" + taskNameSuffix, + "echo \"Installation script is empty. Nothing to be executed.\""); + } + + if (!task.getInstallation().getPreStart().isEmpty()) { + scriptTaskStart.setPreScript(PAFactory.createSimpleScript( + Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + + task.getInstallation().getPreStart(), + "bash")); + } + if (!task.getInstallation().getPostStart().isEmpty()) { + scriptTaskStart.setPostScript(PAFactory.createSimpleScript( + Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + + task.getInstallation().getPostStart(), + "bash")); + } + if (!task.getParentTasks().isEmpty()) { + scriptTaskStart.setVariables(taskVariablesMap); + } + if(scriptTaskInstall != null) { + scriptTaskStart.addDependence(scriptTaskInstall); + } + scriptTaskStart.addGenericInformation("NODE_ACCESS_TOKEN", taskToken); + scriptTasks.add(scriptTaskStart); + } + return scriptTasks; + } + + private ScriptTask createInfraTask(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { + switch (deployment.getDeploymentType()) { + case IAAS: + return createInfraIAASTask(task, deployment, taskNameSuffix, nodeToken); + case BYON: + return createInfraBYONTask(task, deployment, taskNameSuffix, nodeToken); + } + + return new ScriptTask(); + } + + private void addLocalDefaultNSRegexSelectionScript(ScriptTask scriptTask) { + try { + String selectionScriptFileName = "check_node_source_regexp.groovy"; + String[] nodeSourceNameRegex = {"^local$|^Default$"}; + SelectionScript selectionScript = new SelectionScript(Utils.getContentWithFileName(selectionScriptFileName), + "groovy", + nodeSourceNameRegex, + true); + scriptTask.setSelectionScript(selectionScript); + } catch (InvalidScriptException e) { + LOGGER.warn("Selection script could not have been added."); + } + } + + private String createIAASNodeConfigJson(Task task, Deployment deployment) { + ObjectMapper mapper = new ObjectMapper(); + String imageId; + switch (deployment.getPaCloud().getCloudProviderName()) { + case "aws-ec2": + imageId = deployment.getLocationName() + "/" + deployment.getImageProviderId(); + break; + case "openstack": + imageId = deployment.getImageProviderId(); + break; + default: + imageId = deployment.getImageProviderId(); + } + String nodeConfigJson = "{\"image\": \"" + imageId + "\", " + + "\"vmType\": \"" + deployment.getHardwareProviderId() + "\", " + + "\"nodeTags\": \"" + deployment.getNodeName(); + if (task.getPortsToOpen() == null || task.getPortsToOpen().isEmpty()) { + nodeConfigJson += "\"}"; + } else { + try { + nodeConfigJson += "\", \"portsToOpen\": " + mapper.writeValueAsString(task.getPortsToOpen()) + "}"; + } catch (IOException e) { + LOGGER.error(Arrays.toString(e.getStackTrace())); + } + } + return(nodeConfigJson); + } + + private Map createVariablesMapForAcquiringIAASNode(Task task, Deployment deployment, String nodeToken) { + Map variablesMap = new HashMap<>(); + variablesMap.put("NS_name", new TaskVariable("NS_name", + deployment.getPaCloud().getNodeSourceNamePrefix() + deployment.getLocationName())); + variablesMap.put("nVMs", new TaskVariable("nVMs", "1", "PA:Integer", false)); + variablesMap.put("synchronous", new TaskVariable("synchronous", "true", "PA:Boolean", false)); + variablesMap.put("timeout", new TaskVariable("timeout", "700", "PA:Long", false)); + String nodeConfigJson = createIAASNodeConfigJson(task, deployment); + variablesMap.put("nodeConfigJson", new TaskVariable("nodeConfigJson", nodeConfigJson, "PA:JSON", false)); + variablesMap.put("token", new TaskVariable("token", nodeToken)); + + return (variablesMap); + } + + private ScriptTask createInfraIAASTaskForAWS(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { + LOGGER.debug("Acquiring node AWS script file: " + getClass().getResource(File.separator + "acquire_node_aws_script.groovy").toString()); + ScriptTask deployNodeTask = PAFactory.createGroovyScriptTaskFromFile("acquireAWSNode_" + task.getName() + taskNameSuffix, + "acquire_node_aws_script.groovy"); + + deployNodeTask.setPreScript(PAFactory.createSimpleScriptFromFIle("pre_acquire_node_script.groovy", "groovy")); + + Map variablesMap = createVariablesMapForAcquiringIAASNode(task, + deployment, + nodeToken); + LOGGER.debug("Variables to be added to the task acquiring AWS IAAS node: " + variablesMap.toString()); + deployNodeTask.setVariables(variablesMap); + + addLocalDefaultNSRegexSelectionScript(deployNodeTask); + + return deployNodeTask; + } + + private ScriptTask createInfraIAASTaskForOS(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { + LOGGER.debug("Acquiring node OS script file: " + getClass().getResource(File.separator + "acquire_node_aws_script.groovy").toString()); + ScriptTask deployNodeTask = PAFactory.createGroovyScriptTaskFromFile("acquireOSNode_" + task.getName() + taskNameSuffix, + "acquire_node_aws_script.groovy"); + + deployNodeTask.setPreScript(PAFactory.createSimpleScriptFromFIle("pre_acquire_node_script.groovy", "groovy")); + + Map variablesMap = createVariablesMapForAcquiringIAASNode(task, + deployment, + nodeToken); + LOGGER.debug("Variables to be added to the task acquiring OS IAAS node: " + variablesMap.toString()); + deployNodeTask.setVariables(variablesMap); + + addLocalDefaultNSRegexSelectionScript(deployNodeTask); + + return deployNodeTask; + } + + private ScriptTask createInfraIAASTask(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { + switch (deployment.getPaCloud().getCloudProviderName()) { + case "aws-ec2": + return createInfraIAASTaskForAWS(task, deployment, taskNameSuffix, nodeToken); + case "openstack": + return createInfraIAASTaskForOS(task, deployment, taskNameSuffix, nodeToken); + } + return new ScriptTask(); + } + + private ScriptTask createInfraBYONTask(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) { + LOGGER.debug("Acquiring node BYON script file: " + getClass().getResource(File.separator + "acquire_node_BYON_script.groovy").toString()); + ScriptTask deployNodeTask = PAFactory.createGroovyScriptTaskFromFile("acquireBYONNode_" + task.getName() + taskNameSuffix, + "acquire_node_BYON_script.groovy"); + + deployNodeTask.setPreScript(PAFactory.createSimpleScriptFromFIle("pre_acquire_node_script.groovy", "groovy")); + + Map variablesMap = new HashMap<>(); + variablesMap.put("NS_name", new TaskVariable("NS_name", + deployment.getPaCloud().getNodeSourceNamePrefix() + deployment.getLocationName())); + //TODO: To check this. Which ip address is used as host in RM? + variablesMap.put("host_name", new TaskVariable("host_name", + deployment.getByonNode().getIpAddresses().get(0).getValue())); + variablesMap.put("token", new TaskVariable("token", nodeToken)); + + LOGGER.debug("Variables to be added to the task: " + variablesMap.toString()); + deployNodeTask.setVariables(variablesMap); + + addLocalDefaultNSRegexSelectionScript(deployNodeTask); + + return deployNodeTask; + } + + private List createChildScaledTask(Task task, Job job) { + List scriptTasks = new LinkedList<>(); + task.getDeployments().stream().filter(Deployment::getIsDeployed).forEach(deployment -> { + // Creating infra deployment tasks + String token = task.getTaskId() + deployment.getNumber(); + String suffix = "_" + deployment.getNumber(); + scriptTasks.add(createScalingChildUpdateTask(task, suffix, token, job)); + }); + task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); + task.setDeploymentLastSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); + return scriptTasks; + } + + private ScriptTask createScalingChildUpdateTask(Task task, String suffix, String token, Job job) { + ScriptTask scriptTaskUpdate = null; + + Map taskVariablesMap = new HashMap<>(); + //TODO: Taking into consideration multiple parent tasks with multiple communications + taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", + job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); + + if (!task.getInstallation().getUpdateCmd().isEmpty()) { + scriptTaskUpdate = PAFactory.createBashScriptTask(task.getName() + "_update" + suffix, + Utils.getContentWithFileName("export_env_var_script.sh") + SCRIPTS_SEPARATION_BASH + + task.getInstallation().getUpdateCmd()); + } else { + scriptTaskUpdate = PAFactory.createBashScriptTask(task.getName() + "_install" + suffix, + "echo \"Installation script is empty. Nothing to be executed.\""); + } + + scriptTaskUpdate.setPreScript(PAFactory.createSimpleScriptFromFIle("collect_ip_addr_results.groovy", + "groovy")); + + scriptTaskUpdate.setVariables(taskVariablesMap); + scriptTaskUpdate.addGenericInformation("NODE_ACCESS_TOKEN", token); + + return scriptTaskUpdate; + } + + private List buildScaledPATask(Task task, Job job) { + List scriptTasks = new LinkedList<>(); + + task.getDeployments().stream().filter(Deployment::getIsDeployed).forEach(deployment -> { + String token = task.getTaskId() + deployment.getNumber(); + String suffix = "_" + deployment.getNumber(); + + // Creating infra preparation task + scriptTasks.add(createInfraPreparationTask(task, suffix, token, job)); + }); + + task.setDeploymentLastSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); + task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); + + task.getDeployments().stream().filter(deployment -> !deployment.getIsDeployed()).forEach(deployment -> { + // Creating infra deployment tasks + String token = task.getTaskId() + deployment.getNumber(); + String suffix = "_" + deployment.getNumber(); + scriptTasks.add(createInfraTask(task, deployment, suffix, token)); + task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(scriptTasks.size()-1).getName().substring(0, scriptTasks.get(scriptTasks.size()-1).getName().lastIndexOf("_"))); + // If the infrastructure comes with the deployment of the EMS, we set it up. + Optional.ofNullable(deployment.getEmsDeployment()).ifPresent(emsDeploymentRequest -> { + String emsTaskSuffix = "_" + task.getName() + suffix; + ScriptTask emsScriptTask = createEmsDeploymentTask(emsDeploymentRequest,emsTaskSuffix,token); + emsScriptTask.addDependence(scriptTasks.get(scriptTasks.size()-1)); + scriptTasks.add(emsScriptTask); + }); + LOGGER.info("Token added: " + token); + deployment.setIsDeployed(true); + deployment.setNodeAccessToken(token); + + // Creating application deployment tasks + createAndAddAppDeploymentTasks(task, suffix, token, scriptTasks, job); + }); + + scriptTasks.forEach(scriptTask -> task.addSubmittedTaskName(scriptTask.getName())); + + return scriptTasks; + } + + private void createAndAddAppDeploymentTasks(Task task, String suffix, String token, List scriptTasks, Job job) { + List appTasks = createAppTasks(task, suffix, token, job); + task.setDeploymentLastSubmittedTaskName(appTasks.get(appTasks.size()-1).getName().substring(0, appTasks.get(appTasks.size()-1).getName().lastIndexOf(suffix))); + + // Creating infra preparation task + appTasks.add(0, createInfraPreparationTask(task, suffix, token, job)); + appTasks.get(1).addDependence(appTasks.get(0)); + + // Add dependency between infra and application deployment tasks + appTasks.get(0).addDependence(scriptTasks.get(scriptTasks.size()-1)); + + scriptTasks.addAll(appTasks); + } + + private List createParentScaledTask(Task task, Job job) { + List scriptTasks = new LinkedList<>(); + task.getDeployments().stream().filter(Deployment::getIsDeployed).forEach(deployment -> { + // Creating infra deployment tasks + String token = task.getTaskId() + deployment.getNumber(); + String suffix = "_" + deployment.getNumber(); + scriptTasks.add(createScalingParentInfraPreparationTask(task, suffix, token, job)); + }); + task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); + task.setDeploymentLastSubmittedTaskName(scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); + return scriptTasks; + } + + private ScriptTask createScalingParentInfraPreparationTask(Task task, String suffix, String token, Job job) { + ScriptTask prepareInfraTask; + Map taskVariablesMap = new HashMap<>(); + String taskName = "parentPrepareInfra_" + task.getName() + suffix; + + if (!task.getPortsToOpen().isEmpty()) { + prepareInfraTask = PAFactory.createGroovyScriptTaskFromFile(taskName, "post_prepare_infra_script.groovy"); + prepareInfraTask.setPreScript(PAFactory.createSimpleScriptFromFIle("prepare_infra_script.sh", + "bash")); + //TODO: Taking into consideration multiple provided ports + taskVariablesMap.put("providedPortName", new TaskVariable("providedPortName", + task.getPortsToOpen().get(0).getRequestedName())); + taskVariablesMap.put("providedPortValue", new TaskVariable("providedPortValue", + task.getPortsToOpen().get(0).getValue().toString())); + } else { + prepareInfraTask = PAFactory.createBashScriptTask(taskName, + "echo \"No ports to open and not parent tasks. Nothing to be prepared in VM.\""); + } + + prepareInfraTask.setVariables(taskVariablesMap); + prepareInfraTask.addGenericInformation("NODE_ACCESS_TOKEN", token); + + return prepareInfraTask; + } + + private ScriptTask createInfraPreparationTask(Task task, String suffix, String token, Job job) { + ScriptTask prepareInfraTask; + Map taskVariablesMap = new HashMap<>(); + String taskName = "prepareInfra_" + task.getName() + suffix; + + if (!task.getPortsToOpen().isEmpty()) { + prepareInfraTask = PAFactory.createBashScriptTaskFromFile(taskName, "prepare_infra_script.sh"); + prepareInfraTask.setPostScript(PAFactory.createSimpleScript( + Utils.getContentWithFileName("post_prepare_infra_script.groovy") + + SCRIPTS_SEPARATION_GROOVY + Utils.getContentWithFileName("collect_ip_addr_results.groovy"), + "groovy")); + //TODO: Taking into consideration multiple provided ports + taskVariablesMap.put("providedPortName", new TaskVariable("providedPortName", + task.getPortsToOpen().get(0).getRequestedName())); + taskVariablesMap.put("providedPortValue", new TaskVariable("providedPortValue", + task.getPortsToOpen().get(0).getValue().toString())); + if (!task.getParentTasks().isEmpty()) { + //TODO: Taking into consideration multiple parent tasks with multiple communications + taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", + job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); + } + } else if (!task.getParentTasks().isEmpty()) { + prepareInfraTask = PAFactory.createBashScriptTaskFromFile(taskName, "prepare_infra_script.sh"); + prepareInfraTask.setPostScript(PAFactory.createSimpleScript( + Utils.getContentWithFileName("collect_ip_addr_results.groovy"), "groovy")); + //TODO: Taking into consideration multiple parent tasks with multiple communications + taskVariablesMap.put("requestedPortName", new TaskVariable("requestedPortName", + job.findTask(task.getParentTasks().get(0)).getPortsToOpen().get(0).getRequestedName())); + } else { + prepareInfraTask = PAFactory.createBashScriptTask(taskName, + "echo \"No ports to open and not parent tasks. Nothing to be prepared in VM.\""); + } + + if (task.getInstallation().getOperatingSystemType().getOperatingSystemFamily().toLowerCase(Locale.ROOT).equals("ubuntu") && + task.getInstallation().getOperatingSystemType().getOperatingSystemVersion() < 2000) { + LOGGER.info("Adding apt lock handler script since task: " + task.getName() + + " is meant to be executed in: " + + task.getInstallation().getOperatingSystemType().getOperatingSystemFamily() + + " version: " + task.getInstallation().getOperatingSystemType().getOperatingSystemVersion()); + prepareInfraTask.setPreScript(PAFactory.createSimpleScriptFromFIle("wait_for_lock_script.sh", + "bash")); + } + + prepareInfraTask.setVariables(taskVariablesMap); + prepareInfraTask.addGenericInformation("NODE_ACCESS_TOKEN", token); + + return prepareInfraTask; + } + + /** + * Translate a Morphemic task skeleton into a list of ProActive tasks when the job is being scaled out + * @param task A Morphemic task skeleton + * @param job The related job skeleton + * @param scaledTaskName The scaled task name + * @return A list of ProActive tasks + */ + public List buildScalingOutPATask(Task task, Job job, String scaledTaskName) { + List scriptTasks = new LinkedList<>(); + Task scaledTask = job.findTask(scaledTaskName); + + if (scaledTask.getParentTasks().contains(task.getName())) { + // When the scaled task is a child the task to be built + LOGGER.info("Building task " + task.getName() + " as a parent of task " + scaledTaskName); + scriptTasks.addAll(createParentScaledTask(task, job)); + } else { + // Using buildScalingInPATask because it handles all the remaining cases + LOGGER.info("Moving to building with buildScalingInPATask() method"); + scriptTasks.addAll(buildScalingInPATask(task, job, scaledTaskName)); + } + + return scriptTasks; + } + + /** + * Translate a Morphemic task skeleton into a list of ProActive tasks when the job is being scaled in + * @param task A Morphemic task skeleton + * @param job The related job skeleton + * @param scaledTaskName The scaled task name + * @return A list of ProActive tasks + */ + public List buildScalingInPATask(Task task, Job job, String scaledTaskName) { + List scriptTasks = new LinkedList<>(); + + if (scaledTaskName.equals(task.getName())) { + // When the scaled task is the task to be built + LOGGER.info("Building task " + task.getName() + " as it is scaled out"); + scriptTasks.addAll(buildScaledPATask(task, job)); + } else if (task.getParentTasks().contains(scaledTaskName)) { + // When the scaled task is a parent of the task to be built + LOGGER.info("Building task " + task.getName() + " as a child of task " + scaledTaskName); + scriptTasks.addAll(createChildScaledTask(task, job)); + } else { + LOGGER.debug("Task " + task.getName() + " is not impacted by the scaling of task " + scaledTaskName); + } + + return scriptTasks; + } + + /** + * Translate a Morphemic task skeleton into a list of ProActive tasks + * @param task A Morphemic task skeleton + * @param job The related job skeleton + * @return A list of ProActive tasks + */ + public List buildPATask(Task task, Job job) { + List scriptTasks = new LinkedList<>(); + + if (task.getDeployments() == null || task.getDeployments().isEmpty()) { + LOGGER.warn("The task " + task.getName() + " does not have a deployment. It will be scheduled on any free node."); + scriptTasks.addAll(createAppTasks(task, "", "", job)); + task.setDeploymentFirstSubmittedTaskName(scriptTasks.get(0).getName()); + task.setDeploymentLastSubmittedTaskName(scriptTasks.get(scriptTasks.size()-1).getName()); + } + else { + task.getDeployments().stream().filter(deployment -> !deployment.getIsDeployed()).forEach(deployment -> { + // Creating infra deployment tasks + String token = task.getTaskId() + deployment.getNumber(); + String suffix = "_" + deployment.getNumber(); + scriptTasks.add(createInfraTask(task, deployment, suffix, token)); + // If the infrastructure comes with the deployment of the EMS, we set it up. + Optional.ofNullable(deployment.getEmsDeployment()).ifPresent(emsDeploymentRequest -> { + String emsTaskSuffix = "_" + task.getName() + suffix; + ScriptTask emsScriptTask = createEmsDeploymentTask(emsDeploymentRequest,emsTaskSuffix,token); + emsScriptTask.addDependence(scriptTasks.get(scriptTasks.size()-1)); + scriptTasks.add(emsScriptTask); + }); + LOGGER.info("Token added: " + token); + deployment.setIsDeployed(true); + deployment.setNodeAccessToken(token); + + LOGGER.info("+++ Deployment number: " + deployment.getNumber()); + + + // Creating application deployment tasks + createAndAddAppDeploymentTasks(task, suffix, token, scriptTasks, job); + }); + if(!scriptTasks.isEmpty()) { + task.setDeploymentFirstSubmittedTaskName( + scriptTasks.get(0).getName().substring(0, scriptTasks.get(0).getName().lastIndexOf("_"))); + } + } + + scriptTasks.forEach(scriptTask -> task.addSubmittedTaskName(scriptTask.getName())); + + return scriptTasks; + } +} -- GitLab From 5ec84b7d09ffce51944ae11ba6cf9da4cd67832a Mon Sep 17 00:00:00 2001 From: mklkun Date: Wed, 17 Nov 2021 10:59:22 +0100 Subject: [PATCH 2/2] Resolving conflicts with fix-byon-acquire branch modifications --- .../org/activeeon/morphemic/PAGateway.java | 1 + .../morphemic/service/ByonUtils.java | 41 +++++++++++++++++++ .../morphemic/service/TaskBuilder.java | 9 ++-- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java index 9c2ffb5a..ec6808f2 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/PAGateway.java @@ -62,6 +62,7 @@ public class PAGateway { resourceManagerGateway = new PAResourceManagerGateway(paURL); schedulerGateway = new PASchedulerGateway(paURL); connectorIaasGateway = new PAConnectorIaasGateway(paURL); + ByonUtils.init(paURL); } /** diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/ByonUtils.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/ByonUtils.java index a9f774fc..c939a2a5 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/ByonUtils.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/ByonUtils.java @@ -1,16 +1,25 @@ package org.activeeon.morphemic.service; import lombok.extern.slf4j.Slf4j; +import org.activeeon.morphemic.infrastructure.deployment.PAResourceManagerGateway; import org.activeeon.morphemic.model.*; import org.apache.commons.lang3.RandomStringUtils; +import java.util.LinkedList; +import java.util.List; import java.util.Optional; @Slf4j public class ByonUtils { + private static PAResourceManagerGateway resourceManagerGateway; + private ByonUtils() {} + public static void init(String paURL) { + resourceManagerGateway = new PAResourceManagerGateway(paURL); + } + /** * @param byonDef an Object of class ByonDefinition that contains all the nodes Definition * @return an object of class NodeCandidate @@ -86,4 +95,36 @@ public class ByonUtils { * Check if we have to add other variables to the new cloud */ } + + /** + * @param nsName A valid Node Source name + * @return The BYON Host Name + */ + public static String getBYONHostname(String nsName) { + List nodeHostnames = new LinkedList<>(); + try { + nodeHostnames = resourceManagerGateway.getAsyncDeployedNodesInformation(nsName, "hostname"); + } + catch(Exception e) { + LOGGER.error(" resourceManagerGateway threw an exception: " + e); + } + if (nodeHostnames == null) { + LOGGER.error("The node Source "+ nsName + " Does not have any nodes"); + throw new IllegalStateException("Node source is empty no hostname can be retrieved"); + } + else { + if (nodeHostnames.size() != 1) { + if (nodeHostnames.size() == 0) { + LOGGER.error("The node Source " + nsName + " Does not have any nodes"); + throw new IllegalStateException("Node source is empty no hostname can be retrieved"); + } else { + LOGGER.error("The node Source " + nsName + " has more than one node"); + throw new IllegalStateException("Node source has multiple nodes"); + } + } + } + + LOGGER.info("The hostname is retrieved successfully: " + nodeHostnames.get(0)); + return nodeHostnames.get(0); + } } diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java index f9532ba9..ef167f4d 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/service/TaskBuilder.java @@ -266,11 +266,9 @@ public class TaskBuilder { deployNodeTask.setPreScript(PAFactory.createSimpleScriptFromFIle("pre_acquire_node_script.groovy", "groovy")); Map variablesMap = new HashMap<>(); - variablesMap.put("NS_name", new TaskVariable("NS_name", - deployment.getPaCloud().getNodeSourceNamePrefix() + deployment.getLocationName())); - //TODO: To check this. Which ip address is used as host in RM? - variablesMap.put("host_name", new TaskVariable("host_name", - deployment.getByonNode().getIpAddresses().get(0).getValue())); + String NsName = deployment.getPaCloud().getNodeSourceNamePrefix(); + variablesMap.put("NS_name", new TaskVariable("NS_name", NsName)); + variablesMap.put("host_name", new TaskVariable("host_name", ByonUtils.getBYONHostname(NsName))); variablesMap.put("token", new TaskVariable("token", nodeToken)); LOGGER.debug("Variables to be added to the task: " + variablesMap.toString()); @@ -281,6 +279,7 @@ public class TaskBuilder { return deployNodeTask; } + private List createChildScaledTask(Task task, Job job) { List scriptTasks = new LinkedList<>(); task.getDeployments().stream().filter(Deployment::getIsDeployed).forEach(deployment -> { -- GitLab