From b6e7349444a5aa7a9e74ecc81df6791e509af610 Mon Sep 17 00:00:00 2001 From: alijawadfahs Date: Tue, 19 Apr 2022 11:14:04 +0200 Subject: [PATCH 1/5] adding the edge nodes classes and xml --- .../morphemic/model/EdgeDefinition.java | 37 +++ .../activeeon/morphemic/model/EdgeNode.java | 258 ++++++++++++++++++ .../src/main/resources/Define_NS_EDGE.xml | 149 ++++++++++ 3 files changed, 444 insertions(+) create mode 100644 scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeDefinition.java create mode 100644 scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeNode.java create mode 100644 scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeDefinition.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeDefinition.java new file mode 100644 index 00000000..f2b2b93b --- /dev/null +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeDefinition.java @@ -0,0 +1,37 @@ +package org.activeeon.morphemic.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.List; + +/** + * Attributes defining a BYON node + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@ToString(callSuper = true) +public class EdgeDefinition { + @JsonProperty("name") + private String name = null; + + @JsonProperty("systemArch") + private String systemArch = null; + + @JsonProperty("scriptURL") + private String scriptURL = null; + + @JsonProperty("jarURL") + private String jarURL = null; + + @JsonProperty("loginCredential") + private LoginCredential loginCredential = null; + + @JsonProperty("ipAddresses") + private List ipAddresses = null; + + @JsonProperty("nodeProperties") + private NodeProperties nodeProperties = null; +} diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeNode.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeNode.java new file mode 100644 index 00000000..f641922b --- /dev/null +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/EdgeNode.java @@ -0,0 +1,258 @@ +package org.activeeon.morphemic.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.activeeon.morphemic.service.EntityManagerHelper; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.*; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Representation of an Edge used by ProActive + * This class is a clone of the Byon Node Class with some modifications + */ +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Getter +@Setter +@Table(name = "EDGE_NODE") +public class EdgeNode implements Serializable { + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "uuid") + @Column(name = "ID") + @JsonProperty("id") + private String id = null; + + @Column(name = "NAME") + @JsonProperty("name") + private String name = null; + + @Column(name = "SYSTEM_ARCH") + @JsonProperty("systemArch") + private String systemArch = null; + + @JsonProperty("scriptURL") + private String scriptURL = null; + + @JsonProperty("scriptURL") + private String jarURL = null; + + @Embedded + @JsonProperty("loginCredential") + private LoginCredential loginCredential = null; + + @ElementCollection(targetClass=IpAddress.class) + private List ipAddresses = null; + + @Embedded + @JsonProperty("nodeProperties") + private NodeProperties nodeProperties = null; + + @Column(name = "REASON") + @JsonProperty("reason") + private String reason = null; + + @Column(name = "DIAGNOSTIC") + @JsonProperty("diagnostic") + private String diagnostic = null; + + @OneToOne(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.REFRESH) + private NodeCandidate nodeCandidate = null; + + @Column(name = "USER_ID") + @JsonProperty("userId") + private String userId = null; + + @Column(name = "ALLOCATED") + @JsonProperty("allocated") + private Boolean allocated = null; + + @Column(name = "JOB_ID") + @JsonProperty("jobId") + private String jobId; + + public static void clean() { + List allEdgeNodes = EntityManagerHelper.createQuery("SELECT en FROM EdgeNode en", EdgeNode.class).getResultList(); + allEdgeNodes.forEach(EntityManagerHelper::remove); + } + + public EdgeNode name(String name) { + this.name = name; + return this; + } + + /** + * Human-readable name for the node. + * @return name + **/ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public EdgeNode loginCredential(LoginCredential loginCredential) { + this.loginCredential = loginCredential; + return this; + } + + /** + * Get loginCredential + * @return loginCredential + **/ + public LoginCredential getLoginCredential() { + return loginCredential; + } + + public void setLoginCredential(LoginCredential loginCredential) { + this.loginCredential = loginCredential; + } + + public EdgeNode ipAddresses(List ipAddresses) { + this.ipAddresses = ipAddresses; + return this; + } + + public EdgeNode addIpAddressesItem(IpAddress ipAddressesItem) { + if (this.ipAddresses == null) { + this.ipAddresses = new ArrayList(); + } + this.ipAddresses.add(ipAddressesItem); + return this; + } + + /** + * The public/private ip addresses under which this node is reachable. + * @return ipAddresses + **/ + public List getIpAddresses() { + return ipAddresses; + } + + public void setIpAddresses(List ipAddresses) { + this.ipAddresses = ipAddresses; + } + + public EdgeNode nodeProperties(NodeProperties nodeProperties) { + this.nodeProperties = nodeProperties; + return this; + } + + /** + * Further properties of this node. + * @return nodeProperties + **/ + public NodeProperties getNodeProperties() { + return nodeProperties; + } + + public void setNodeProperties(NodeProperties nodeProperties) { + this.nodeProperties = nodeProperties; + } + + public EdgeNode reason(String reason) { + this.reason = reason; + return this; + } + + + + public EdgeNode diagnostic(String diagnostic) { + this.diagnostic = diagnostic; + return this; + } + + + public EdgeNode id(String id) { + this.id = id; + return this; + } + + public EdgeNode userId(String userId) { + this.userId = userId; + return this; + } + + + public EdgeNode allocated(Boolean allocated) { + this.allocated = allocated; + return this; + } + + /** + * Signals if the node was allocated by cloudiator + * @return allocated + **/ + public Boolean isAllocated() { + return allocated; + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EdgeNode edgeNode = (EdgeNode) o; + return Objects.equals(this.name, edgeNode.name) && + Objects.equals(this.loginCredential, edgeNode.loginCredential) && + Objects.equals(this.ipAddresses, edgeNode.ipAddresses) && + Objects.equals(this.nodeProperties, edgeNode.nodeProperties) && + Objects.equals(this.reason, edgeNode.reason) && + Objects.equals(this.diagnostic, edgeNode.diagnostic) && + Objects.equals(this.nodeCandidate, edgeNode.nodeCandidate) && + Objects.equals(this.id, edgeNode.id) && + Objects.equals(this.userId, edgeNode.userId) && + Objects.equals(this.allocated, edgeNode.allocated) && + Objects.equals(this.jobId, edgeNode.jobId); + } + + @Override + public int hashCode() { + return Objects.hash(name, loginCredential, ipAddresses, nodeProperties, reason, diagnostic, nodeCandidate, id, userId, allocated); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class EdgeNode {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" loginCredential: ").append(toIndentedString(loginCredential)).append("\n"); + sb.append(" ipAddresses: ").append(toIndentedString(ipAddresses)).append("\n"); + sb.append(" nodeProperties: ").append(toIndentedString(nodeProperties)).append("\n"); + sb.append(" reason: ").append(toIndentedString(reason)).append("\n"); + sb.append(" diagnostic: ").append(toIndentedString(diagnostic)).append("\n"); + sb.append(" nodeCandidate: ").append(toIndentedString(nodeCandidate)).append("\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" userId: ").append(toIndentedString(userId)).append("\n"); + sb.append(" allocated: ").append(toIndentedString(allocated)).append("\n"); + sb.append(" jobId: ").append(toIndentedString(jobId)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml b/scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml new file mode 100644 index 00000000..7637b510 --- /dev/null +++ b/scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 508.96875 + + + 515.5 + + + + + + + + + + + + + + + + ]]> + + + \ No newline at end of file -- GitLab From 750c18b86c18b50f790e4ecac364dd7447eba1c2 Mon Sep 17 00:00:00 2001 From: alijawadfahs Date: Tue, 19 Apr 2022 11:17:28 +0200 Subject: [PATCH 2/5] adding the edge node type --- .../activeeon/morphemic/model/CloudType.java | 2 ++ .../activeeon/morphemic/model/Deployment.java | 20 +++++++++++++ .../morphemic/model/NodeCandidate.java | 2 ++ .../activeeon/morphemic/model/NodeType.java | 30 +++++++++++++++++-- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/CloudType.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/CloudType.java index f9fafdeb..56dffb2d 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/CloudType.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/CloudType.java @@ -16,6 +16,8 @@ public enum CloudType { BYON("BYON"), + EDGE("EDGE"), + SIMULATION("SIMULATION"); private String value; diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/Deployment.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/Deployment.java index cdbdacab..3fd99a2a 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/Deployment.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/Deployment.java @@ -62,6 +62,10 @@ public class Deployment implements Serializable { @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH) private ByonNode byonNode; + @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH) + private EdgeNode edgeNode; + + public static void clean() { List allDeployments = EntityManagerHelper.createQuery("SELECT d FROM Deployment d", Deployment.class).getResultList(); allDeployments.forEach(EntityManagerHelper::remove); @@ -101,6 +105,22 @@ public class Deployment implements Serializable { ", task='" + task.getName() + '\'' + ", byonNode='" + byonNode.getName() + '\'' + '}'; + + case EDGE: + return "Deployment{" + + "nodeName='" + nodeName + '\'' + + ", locationName='" + locationName + '\'' + + ", imageProviderId='" + imageProviderId + '\'' + + ", hardwareProviderId='" + hardwareProviderId + '\'' + + ", isDeployed='" + isDeployed.toString() + '\'' + + ", instanceId='" + instanceId + '\'' + + ", ipAddress='" + ipAddress + '\'' + + ", nodeAccessToken='" + nodeAccessToken + '\'' + + ", number='" + number + '\'' + + ", paCloud='" + paCloud + '\'' + + ", task='" + task.getName() + '\'' + + ", edgeNode='" + edgeNode.getName() + '\'' + + '}'; default: return "Deployment{nodeName='" + nodeName + '}'; } diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeCandidate.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeCandidate.java index abe81c48..8808e60c 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeCandidate.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeCandidate.java @@ -48,6 +48,8 @@ public class NodeCandidate implements Serializable { BYON("BYON"), + EDGE("EDGE"), + SIMULATION("SIMULATION"); private String value; diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeType.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeType.java index c3899c47..971bc1b5 100644 --- a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeType.java +++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/model/NodeType.java @@ -43,13 +43,23 @@ public enum NodeType implements Enumerator { * * @see #BYON_VALUE */ - BYON(3, "BYON", "BYON"), /** + BYON(3, "BYON", "BYON"), + + /** + * The 'EDGE' literal object. + * + * + * @see #EDGE_VALUE + */ + EDGE(4, "EDGE", "EDGE"), /** + + /** * The 'SIMULATION' literal object. * * * @see #SIMULATION_VALUE */ - SIMULATION(4, "SIMULATION", "SIMULATION"); + SIMULATION(5, "SIMULATION", "SIMULATION"); /** * The 'IAAS' literal value. @@ -99,6 +109,18 @@ public enum NodeType implements Enumerator { */ public static final int BYON_VALUE = 3; + /** + * The 'EDGE' literal value. + * + *

+ * If the meaning of 'EDGE' literal object isn't clear, + * there really should be more of a description here... + *

+ * + * @see #EDGE + */ + public static final int EDGE_VALUE = 4; + /** * The 'SIMULATION' literal value. * @@ -109,7 +131,7 @@ public enum NodeType implements Enumerator { * * @see #SIMULATION */ - public static final int SIMULATION_VALUE = 4; + public static final int SIMULATION_VALUE = 5; /** * An array of all the 'Node Type' enumerators. @@ -122,6 +144,7 @@ public enum NodeType implements Enumerator { PAAS, FAAS, BYON, + EDGE, SIMULATION, }; @@ -179,6 +202,7 @@ public enum NodeType implements Enumerator { case PAAS_VALUE: return PAAS; case FAAS_VALUE: return FAAS; case BYON_VALUE: return BYON; + case EDGE_VALUE: return EDGE; case SIMULATION_VALUE: return SIMULATION; } return null; -- GitLab From 20da4ad137ac759f5d46618d8c904dbcef80d05f Mon Sep 17 00:00:00 2001 From: alijawadfahs Date: Tue, 19 Apr 2022 11:26:44 +0200 Subject: [PATCH 3/5] adding the edge endpoints --- .../org/activeeon/morphemic/PAGateway.java | 187 +++++++++++++++++- .../morphemic/service/ByonUtils.java | 117 ++++++----- .../src/main/resources/Define_NS_BYON.xml | 8 +- 3 files changed, 260 insertions(+), 52 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 269054a7..82d8bd42 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 @@ -536,6 +536,74 @@ public class PAGateway { TemporaryFilesHelper.delete(fXmlFile); } + /** + * Define a EDGE node source + * @param edgeNodeList a list of EDGE nodes to be connected to the server. + * @param nodeSourceName The name of the node source + */ + public void defineEdgeNodeSource(List edgeNodeList, String nodeSourceName) { + Map variables = new HashMap<>(); + String filename; + String EdgeIPs = ""; + // Prepare the ip addresses for all the nodes to be added + for(EdgeNode edgeNode: edgeNodeList){ + List tempListIP=edgeNode.getIpAddresses(); + assert !tempListIP.isEmpty(); + EdgeIPs= EdgeIPs + tempListIP.get(0).getValue().replace(" ", "") + ","; + } + // Collect the pamr router address and port number + try { + URL endpointPa = (new URL(this.paURL)); + variables.put("rm_host_name", endpointPa.getHost()); + variables.put("pa_port", "" + endpointPa.getPort()); + } catch (MalformedURLException e) { + LOGGER.error(String.valueOf(e.getStackTrace())); + } + + assert !edgeNodeList.isEmpty(); + EdgeNode edgeNode = edgeNodeList.get(0); + filename = File.separator + "Define_NS_EDGE.xml"; + variables.put("NS_name", nodeSourceName); + variables.put("pa_protocol", "http"); + variables.put("tokens", "EDGE_" + edgeNode.getJobId()); + variables.put("ssh_username", edgeNode.getLoginCredential().getUsername()); + variables.put("ssh_password", edgeNode.getLoginCredential().getPassword()); + /* IMPORTANT: Later we should relay only on the ssh_key. For now all the nodes must have the same login + credentials. later by automating the node deployment process we can add the server key automatically. + TODO */ + variables.put("ssh_key", ""); + variables.put("ssh_port", "22"); + variables.put("list_of_ips", EdgeIPs); + switch (edgeNode.getSystemArch()) { + case "AMD": + variables.put("deployment_mode", "useStartupScript"); + variables.put("script_url", edgeNode.getScriptURL()); + variables.put("script_path", "/tmp/proactive-agent.sh"); + break; + case "ARM": + variables.put("deployment_mode", "useNodeJarStartupScript"); + variables.put("jar_url", edgeNode.getJarURL()); + break; + default: + LOGGER.error("The Edge node system architecture {} is not supported!", edgeNode.getSystemArch()); + } + + // Create the xml file + File fXmlFile = null; + LOGGER.info("NodeSource deployment workflow filename: " + filename); + try { + fXmlFile = TemporaryFilesHelper.createTempFileFromResource(filename); + } catch (IOException ioe) { + LOGGER.error("Opening the NS deployment workflow file failed due to : " + Arrays.toString(ioe.getStackTrace())); + } + assert fXmlFile != null; + LOGGER.info("Submitting the file: " + fXmlFile.toString()); + LOGGER.info("Trying to deploy the NS: " + nodeSourceName); + JobId jobId = schedulerGateway.submit(fXmlFile, variables); + LOGGER.info("Job submitted with ID: " + jobId); + TemporaryFilesHelper.delete(fXmlFile); + } + /** * Add an EMS deployment to a defined job * @param nodeNames Names of the nodes to which to add EMS deployment @@ -656,14 +724,14 @@ public class PAGateway { * @param byonNodeDefinition objects of class ByonDefinition that contains the detials of the nodes to be registered. * @param jobId A constructed job identifier * @param Automate the Byon agent will be deployed automatically if the value is set to True - * @return ByonNodeList objects of class ByonNode that contains information about the registered Node + * @return newByonNode object of class ByonNode that contains information about the registered Node */ public ByonNode registerNewByonNode(ByonDefinition byonNodeDefinition, String jobId, boolean Automate) { Validate.notNull(byonNodeDefinition, "The received Byon node definition is empty. Nothing to be registered."); Validate.notNull(jobId, "The received jobId is empty. Nothing to be registered."); LOGGER.info("registerNewByonNode endpoint is called with Automate set to " + Automate + ", Registering a new BYON definition related to job " + jobId + " ..."); - NodeCandidate byonNC = ByonUtils.createByonNodeCandidate(byonNodeDefinition, jobId); + NodeCandidate byonNC = ByonUtils.createNodeCandidate(byonNodeDefinition.getNodeProperties(), jobId, "byon"); EntityManagerHelper.begin(); ByonNode newByonNode = new ByonNode(); newByonNode.setName(byonNodeDefinition.getName()); @@ -687,6 +755,42 @@ public class PAGateway { } + /** + * Register new Edge nodes passed as EdgeDefinition object + * + * @param edgeNodeDefinition objects of class ByonDefinition that contains the detials of the nodes to be registered. + * @param jobId A constructed job identifier + * @return newEdgeNode object of class EdgeNode that contains information about the registered Node + */ + public EdgeNode registerNewEdgeNode(EdgeDefinition edgeNodeDefinition, String jobId) { + Validate.notNull(edgeNodeDefinition, "The received EDGE node definition is empty. Nothing to be registered."); + Validate.notNull(jobId, "The received jobId is empty. Nothing to be registered."); + LOGGER.info("registerNewEdgeNode endpoint is called, Registering a new EDGE definition related to job " + jobId + " ..."); + + EntityManagerHelper.begin(); + EdgeNode newEdgeNode = new EdgeNode(); + newEdgeNode.setName(edgeNodeDefinition.getName()); + newEdgeNode.setLoginCredential(edgeNodeDefinition.getLoginCredential()); + newEdgeNode.setIpAddresses(edgeNodeDefinition.getIpAddresses()); + newEdgeNode.setNodeProperties(edgeNodeDefinition.getNodeProperties()); + newEdgeNode.setJobId(jobId); + newEdgeNode.setSystemArch(edgeNodeDefinition.getSystemArch()); + newEdgeNode.setScriptURL(edgeNodeDefinition.getScriptURL()); + newEdgeNode.setJarURL(edgeNodeDefinition.getJarURL()); + + NodeCandidate edgeNC = ByonUtils.createNodeCandidate(edgeNodeDefinition.getNodeProperties(), jobId, "edge"); + newEdgeNode.setNodeCandidate(edgeNC); + + EntityManagerHelper.persist(newEdgeNode); + EntityManagerHelper.commit(); + LOGGER.info("EDGE node registered."); + + return newEdgeNode; + /* TODO: + * Avoid duplicate nodes in the database + */ + } + /** * Return the List of registered BYON nodes @@ -711,6 +815,31 @@ public class PAGateway { */ } + + /** + * Return the List of registered EDGE nodes + * @param jobId A constructed job identifier, If "0" is passed as the JobId all the Edge Nodes will be returned + * @return List of EdgeNode objects that contains information about the registered Nodes + */ + public List getEdgeNodeList(String jobId) { + List filteredEdgeNodes = new LinkedList<>(); + List listEdgeNodes = EntityManagerHelper.createQuery("SELECT edge FROM EdgeNode edge", EdgeNode.class).getResultList(); + if (jobId.equals("0")) { + return listEdgeNodes; + } else { + for (EdgeNode edgeNode : listEdgeNodes) { + if (jobId.equals(edgeNode.getJobId())) { + filteredEdgeNodes.add(edgeNode); + } + } + return filteredEdgeNodes; + } + /*TODO: + * Add Logging info + */ + } + + /** * Adding BYON nodes to a job component * @param byonIdPerComponent a mapping between byon nodes and job components @@ -763,6 +892,59 @@ public class PAGateway { return 0; } + + /** + * Adding EDGE nodes to a job component + * @param edgeIdPerComponent a mapping between byon nodes and job components + * @param jobId A constructed job identifier + * @return 0 if nodes has been added properly. A greater than 0 value otherwise. + */ + public int addEdgeNodes(Map edgeIdPerComponent, String jobId) { + Validate.notNull(edgeIdPerComponent, "The received byonIdPerComponent structure is empty. Nothing to be added."); + + EntityManagerHelper.begin(); + edgeIdPerComponent.forEach((edgeNodeId, componentName) -> { + EdgeNode edgeNode = EntityManagerHelper.find(EdgeNode.class, edgeNodeId); + Task task = EntityManagerHelper.find(Task.class, jobId + componentName); + + assert edgeNode!=null : "The EDGE ID passed in the mapping does not exist in the database"; + assert task!=null : "The componentId passed in the mapping does not exist in the database"; + + Deployment newDeployment = new Deployment(); + newDeployment.setNodeName(edgeNode.getName()); + newDeployment.setDeploymentType(NodeType.EDGE); + newDeployment.setEdgeNode(edgeNode); + + PACloud cloud = new PACloud(); + String nodeSourceName = "EDGE_NS_" + edgeNode.getId(); + cloud.setCloudID(nodeSourceName); + cloud.setNodeSourceNamePrefix(nodeSourceName); + cloud.setCloudType(CloudType.EDGE); + cloud.addDeployment(newDeployment); + newDeployment.setPaCloud(cloud); + EntityManagerHelper.persist(cloud); + + List edgeNodeList = new LinkedList<>(); + edgeNodeList.add(edgeNode); + LOGGER.info("EDGE node Added: " + edgeNode.getName() + " Ip: " + edgeNode.getIpAddresses().get(0).getValue()); + defineEdgeNodeSource(edgeNodeList, nodeSourceName); + LOGGER.info("EDGE node source EDGE_NS_" + edgeNode.getId() + " is defined"); + + newDeployment.setTask(task); + newDeployment.setNumber(task.getNextDeploymentID()); + EntityManagerHelper.persist(newDeployment); + LOGGER.debug("Deployment created: " + newDeployment.toString()); + + task.addDeployment(newDeployment); + EntityManagerHelper.persist(task); + }); + + EntityManagerHelper.commit(); + + LOGGER.info("EDGE nodes added properly."); + return 0; + } + /** * Undeploy clouds * @param cloudIDs List of cloud IDs to remove @@ -1127,6 +1309,7 @@ public class PAGateway { null, null, NodeType.IAAS, + null, null ); }) 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 fc79d300..a17eb602 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 @@ -28,75 +28,96 @@ public class ByonUtils { } /** - * @param byonDef an Object of class ByonDefinition that contains all the nodes Definition + * @param np an Object of class NodeProperties that contains all the nodes properties needed for the candidate declaration + * @param jobId a String identifier of the node candidate job + * @param nodeType a String of the node type (byon or edge) * @return an object of class NodeCandidate */ - public static NodeCandidate createByonNodeCandidate(ByonDefinition byonDef, String jobId) { - LOGGER.debug("Creating the BYON node candidate ..."); - //create a dummy cloud - Cloud byonCloud = ByonUtils.getOrCreateDummyByonCloud(); + public static NodeCandidate createNodeCandidate(NodeProperties np, String jobId, String nodeType) { EntityManagerHelper.begin(); - //set the image - Image image = new Image(); - image.setId("byon-image-" + RandomStringUtils.randomAlphanumeric(16)); - image.setOperatingSystem(byonDef.getNodeProperties().getOperatingSystem()); + LOGGER.debug("Creating the {} node candidate ...", nodeType.toUpperCase()); + //Start by setting the universal nodes properties + NodeCandidate nc = new NodeCandidate(); + nc.setJobIdForBYON(jobId); + nc.setPrice(0.0); + nc.setMemoryPrice(0.0); + nc.setPricePerInvocation(0.0); - //set the hardware + //create a dummy cloud definition for BYON nodes + Cloud dummyCloud = new Cloud(); + dummyCloud = ByonUtils.getOrCreateDummyCloud(nodeType); + //Create a dummy image + Image image = new Image(); + image.setOperatingSystem(np.getOperatingSystem()); + //Define the hardware Hardware hardware = new Hardware(); - hardware.setId("byon-hardware-" + RandomStringUtils.randomAlphanumeric(16)); - hardware.setCores(byonDef.getNodeProperties().getNumberOfCores()); - hardware.setDisk((double) byonDef.getNodeProperties().getDisk()); - hardware.setRam(byonDef.getNodeProperties().getMemory()); - - //set the location + hardware.setCores(np.getNumberOfCores()); + hardware.setDisk((double) np.getDisk()); + hardware.setRam(np.getMemory()); + //Define the location Location location = new Location(); - location.setId("byon-location-" + RandomStringUtils.randomAlphanumeric(16)); - location.setGeoLocation(byonDef.getNodeProperties().getGeoLocation()); - - //define a dummy NC - NodeCandidate byonNC = new NodeCandidate(); - byonNC.setNodeCandidateType(NodeCandidate.NodeCandidateTypeEnum.BYON); - byonNC.setJobIdForBYON(jobId); - byonNC.setPrice(0.0); - byonNC.setMemoryPrice(0.0); - byonNC.setPricePerInvocation(0.0); - byonNC.setCloud(byonCloud); - byonNC.setImage(image); - byonNC.setHardware(hardware); - byonNC.setLocation(location); - - EntityManagerHelper.persist(byonNC); - EntityManagerHelper.commit(); - LOGGER.info("BYON node candidate created."); - return byonNC; + location.setGeoLocation(np.getGeoLocation()); + + //Define the properties that depend on the node type + + if (nodeType.equals("byon")) { + + //set the image name + image.setId("byon-image-" + RandomStringUtils.randomAlphanumeric(16)); + //set the hardware + hardware.setId("byon-hardware-" + RandomStringUtils.randomAlphanumeric(16)); + //set the location + location.setId("byon-location-" + RandomStringUtils.randomAlphanumeric(16)); + //set the nc parameters + nc.setNodeCandidateType(NodeCandidate.NodeCandidateTypeEnum.BYON); + + } + else { //the node type is EDGE + + //set the image name + image.setId("edge-image-" + RandomStringUtils.randomAlphanumeric(16)); + //set the hardware + hardware.setId("edge-hardware-" + RandomStringUtils.randomAlphanumeric(16)); + //set the location + location.setId("edge-location-" + RandomStringUtils.randomAlphanumeric(16)); + //set the nc parameters + nc.setNodeCandidateType(NodeCandidate.NodeCandidateTypeEnum.EDGE); + } + + nc.setCloud(dummyCloud); + nc.setImage(image); + nc.setHardware(hardware); + nc.setLocation(location); + EntityManagerHelper.persist(nc); + LOGGER.info("{} node candidate created.", nodeType.toUpperCase()); + return nc; } /** * Create a dummy object of class Cloud to be used for the node candidates * @return the created byonCloud object */ - public static Cloud getOrCreateDummyByonCloud() { - LOGGER.debug("Searching for the dummy BYON cloud ..."); + public static Cloud getOrCreateDummyCloud(String nodeType) { + LOGGER.debug("Searching for the dummy cloud ..."); EntityManagerHelper.begin(); //Check if the Byon cloud already exists - Optional optCloud = Optional.ofNullable(EntityManagerHelper.find(Cloud.class, "byon")); + Optional optCloud = Optional.ofNullable(EntityManagerHelper.find(Cloud.class, nodeType)); if (optCloud.isPresent()) { - LOGGER.info("Dummy BYON cloud found!"); + LOGGER.info("Dummy cloud for {} was found!", nodeType); return optCloud.get(); } - LOGGER.debug("Creating the dummy BYON cloud ..."); + LOGGER.debug("Creating the dummy cloud for {} Nodes ...", nodeType); //else, Byon cloud will be created - Cloud byonCloud = new Cloud(); - byonCloud.setCloudType(CloudType.BYON); - byonCloud.setOwner("BYON"); - byonCloud.setId("byon"); + Cloud newCloud = new Cloud(); + newCloud.setCloudType((nodeType.equals("byon")) ? CloudType.BYON : CloudType.EDGE); + newCloud.setOwner((nodeType.equals("byon")) ? "BYON" : "EDGE"); + newCloud.setId(nodeType); //Add the Byon cloud to the database - EntityManagerHelper.persist(byonCloud); - EntityManagerHelper.commit(); - LOGGER.info("Dummy BYON cloud created."); - return byonCloud; + EntityManagerHelper.persist(newCloud); + LOGGER.info("Dummy {} cloud created.", nodeType.toUpperCase()); + return newCloud; /* TODO : * Check if we have to add other variables to the new cloud diff --git a/scheduling-abstraction-layer/src/main/resources/Define_NS_BYON.xml b/scheduling-abstraction-layer/src/main/resources/Define_NS_BYON.xml index 5dec694c..463f71ff 100644 --- a/scheduling-abstraction-layer/src/main/resources/Define_NS_BYON.xml +++ b/scheduling-abstraction-layer/src/main/resources/Define_NS_BYON.xml @@ -1,7 +1,7 @@ + xmlns="urn:proactive:jobdescriptor:3.12" xsi:schemaLocation="urn:proactive:jobdescriptor:3.12 http://www.activeeon.com/public_content/schemas/proactive/jobdescriptor/3.12/schedulerjob.xsd" name="Define_NS_BYON" priority="normal" onTaskError="continueJobExecution" maxNumberOfExecution="2" > @@ -75,7 +75,11 @@ def infrastructureParameters = ["300000", //Node Time out "/opt/ProActive_node_agent/jre/bin/java", //JavaPath on the remote host "/opt/ProActive_node_agent", //ScheduligPath on the remote hosts "Linux", //targetOs - javaOptions]//Java options + javaOptions, //Java options + "autoGenerated", //deploymentMode + "", //nodeJarUrl + "", //startupScriptStandard + ""] //startupScriptWithNodeJarDownload def infrastructureFileParameters = [hosts, //hostsList file content "", //SSH Private Key -- GitLab From 1d47c2904501aeff7a9cf52ab505266ceedbe07a Mon Sep 17 00:00:00 2001 From: alijawadfahs Date: Thu, 28 Apr 2022 02:34:33 +0200 Subject: [PATCH 4/5] Adding support for ARM nodes using node.jar --- .../java/org/activeeon/morphemic/PAGateway.java | 12 ++++++++++-- .../src/main/resources/Define_NS_EDGE.xml | 15 +++++++++------ 2 files changed, 19 insertions(+), 8 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 82d8bd42..77b78fa6 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 @@ -580,9 +580,15 @@ public class PAGateway { variables.put("script_url", edgeNode.getScriptURL()); variables.put("script_path", "/tmp/proactive-agent.sh"); break; - case "ARM": + case "ARMv7": variables.put("deployment_mode", "useNodeJarStartupScript"); variables.put("jar_url", edgeNode.getJarURL()); + variables.put("jre_url", "https://ci-materials.s3.amazonaws.com/Latest_jre/jre-8u322b06-linux-arm.tar.gz"); + break; + case "ARMv8": + variables.put("deployment_mode", "useNodeJarStartupScript"); + variables.put("jar_url", edgeNode.getJarURL()); + variables.put("jre_url", "https://ci-materials.s3.amazonaws.com/Latest_jre/jre-8u322b06-linux-aarch64.tar.gz"); break; default: LOGGER.error("The Edge node system architecture {} is not supported!", edgeNode.getSystemArch()); @@ -916,7 +922,7 @@ public class PAGateway { newDeployment.setEdgeNode(edgeNode); PACloud cloud = new PACloud(); - String nodeSourceName = "EDGE_NS_" + edgeNode.getId(); + String nodeSourceName = "EDGE_"+edgeNode.getSystemArch()+"_NS_" + edgeNode.getId(); cloud.setCloudID(nodeSourceName); cloud.setNodeSourceNamePrefix(nodeSourceName); cloud.setCloudType(CloudType.EDGE); @@ -1708,6 +1714,8 @@ public class PAGateway { Location.clean(); LOGGER.info("Cleaning ByonNodes ..."); ByonNode.clean(); + LOGGER.info("Cleaning EdgeNodes ..."); + EdgeNode.clean(); EntityManagerHelper.commit(); LOGGER.info("Done."); } diff --git a/scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml b/scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml index 7637b510..f21e6820 100644 --- a/scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml +++ b/scheduling-abstraction-layer/src/main/resources/Define_NS_EDGE.xml @@ -17,6 +17,7 @@ @@ -50,12 +51,12 @@ def sshKey = variables.get("ssh_key") def sshPort = variables.get("ssh_port") def ips= variables.get("list_of_ips") def deploymentMode=variables.get("deployment_mode") -def scriptURL=variables.get("script_url")//"https://raw.githubusercontent.com/alijawadfahs/Byon-setup/main/scripts/configure-byon-Debian-test.sh" -def scriptPath=variables.get("script_path")//"/tmp/proactive-agent.sh" -def defaultStartupScript="%detachedModePrefix% %javaPath% %javaOptions% -Dfile.encoding=%fileEncoding% -cp .:%schedulingPath%/addons:%schedulingPath%/addons/*:%schedulingPath%/dist/lib/* org.ow2.proactive.resourcemanager.utils.RMNodeStarter -n %nodeName% -s %nodeSourceName% -r %rmUrl% -w %numberOfNodesPerInstance% -v %credentials% &" -def nodeJarUrl=variables.get("jar_url")//"" -def startupScriptWithNodeJarDownload="" +def scriptURL=variables.get("script_url") +def scriptPath=variables.get("script_path") +def nodeJarUrl=variables.get("jar_url") +def jreURL=variables.get("jre_url") def javaOptions = "-Dproactive.net.nolocal=true -Dproactive.communication.protocol=pamr -Dproactive.useIPaddress=true -Dproactive.pamr.router.address=" + host + ips = ips.split(",") def hosts = "" for (ip in ips) { @@ -69,7 +70,9 @@ else { tokens="tokens="+tokens } -def startupScriptStandard = "wget -nv -O "+scriptPath+" "+scriptURL+"; chmod +x "+scriptPath+"; "+scriptPath+"; "+defaultStartupScript +def defaultStartupScript="%detachedModePrefix% %javaPath% %javaOptions% -Dfile.encoding=%fileEncoding% -cp .:%schedulingPath%/addons:%schedulingPath%/addons/*:%schedulingPath%/dist/lib/* org.ow2.proactive.resourcemanager.utils.RMNodeStarter -n %nodeName% -s %nodeSourceName% -r %rmUrl% -w %numberOfNodesPerInstance% -v %credentials% &" +def startupScriptWithNodeJarDownload= "if [ -d /tmp/node ]; then rm -rf /tmp/node; fi;\r\nmkdir -p /tmp/node && cd /tmp/node;\r\nwget -nv -O jre.tar.gz -N "+jreURL+"; mkdir jre;tar -xf jre.tar.gz --strip-components=1 -C jre;\r\nwget -nv --no-check-certificate -O node.jar %nodeJarUrl%\r\n%detachedModePrefix% jre/bin/java -jar node.jar %javaOptions% -Dpython.path=%jythonPath% -r %rmUrl% -n %nodeName% -s %nodeSourceName% -w %numberOfNodesPerInstance% -v %credentials% &" +def startupScriptStandard = "wget -nv -O "+scriptPath+" "+scriptURL+";\r\nchmod +x "+scriptPath+";\r\n"+scriptPath+";\r\n"+defaultStartupScript println "[+] Preparation of NodeSoure " + nodeSourceName print "(1/4) Connecting to the RM at "+protocol+"://"+host+":"+port+"/ ..." -- GitLab From 3a75ec24e197015213e038419e91bb0c39f6d8d2 Mon Sep 17 00:00:00 2001 From: alijawadfahs Date: Thu, 5 May 2022 09:49:54 +0200 Subject: [PATCH 5/5] addressing the comments --- .../java/org/activeeon/morphemic/PAGateway.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 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 77b78fa6..fc2bfcb5 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 @@ -485,7 +485,7 @@ public class PAGateway { * @param byonNodeList a list of BYON nodes to be connected to the server. * @param nodeSourceName The name of the node source */ - public void defineByonNodeSource(List byonNodeList, String nodeSourceName) { + private void defineByonNodeSource(List byonNodeList, String nodeSourceName) { Map variables = new HashMap<>(); String filename; String byonIPs = ""; @@ -537,19 +537,19 @@ public class PAGateway { } /** - * Define a EDGE node source + * Define an EDGE node source * @param edgeNodeList a list of EDGE nodes to be connected to the server. * @param nodeSourceName The name of the node source */ - public void defineEdgeNodeSource(List edgeNodeList, String nodeSourceName) { + private void defineEdgeNodeSource(List edgeNodeList, String nodeSourceName) { Map variables = new HashMap<>(); String filename; - String EdgeIPs = ""; + String edgeIPs = ""; // Prepare the ip addresses for all the nodes to be added for(EdgeNode edgeNode: edgeNodeList){ List tempListIP=edgeNode.getIpAddresses(); assert !tempListIP.isEmpty(); - EdgeIPs= EdgeIPs + tempListIP.get(0).getValue().replace(" ", "") + ","; + edgeIPs= edgeIPs + tempListIP.get(0).getValue().replace(" ", "") + ","; } // Collect the pamr router address and port number try { @@ -573,7 +573,7 @@ public class PAGateway { TODO */ variables.put("ssh_key", ""); variables.put("ssh_port", "22"); - variables.put("list_of_ips", EdgeIPs); + variables.put("list_of_ips", edgeIPs); switch (edgeNode.getSystemArch()) { case "AMD": variables.put("deployment_mode", "useStartupScript"); @@ -592,6 +592,7 @@ public class PAGateway { break; default: LOGGER.error("The Edge node system architecture {} is not supported!", edgeNode.getSystemArch()); + throw new IllegalArgumentException("The Edge node system architecture " + edgeNode.getSystemArch() + " is not supported!"); } // Create the xml file @@ -730,7 +731,7 @@ public class PAGateway { * @param byonNodeDefinition objects of class ByonDefinition that contains the detials of the nodes to be registered. * @param jobId A constructed job identifier * @param Automate the Byon agent will be deployed automatically if the value is set to True - * @return newByonNode object of class ByonNode that contains information about the registered Node + * @return newByonNode ByonNode object that contains information about the registered Node */ public ByonNode registerNewByonNode(ByonDefinition byonNodeDefinition, String jobId, boolean Automate) { Validate.notNull(byonNodeDefinition, "The received Byon node definition is empty. Nothing to be registered."); @@ -766,7 +767,7 @@ public class PAGateway { * * @param edgeNodeDefinition objects of class ByonDefinition that contains the detials of the nodes to be registered. * @param jobId A constructed job identifier - * @return newEdgeNode object of class EdgeNode that contains information about the registered Node + * @return newEdgeNode EdgeNode object that contains information about the registered Node */ public EdgeNode registerNewEdgeNode(EdgeDefinition edgeNodeDefinition, String jobId) { Validate.notNull(edgeNodeDefinition, "The received EDGE node definition is empty. Nothing to be registered."); -- GitLab