zuul update

Change-Id: I12e48440e6eb4dd37000e10e6ccd36fbe189e5df
This commit is contained in:
Marta 2024-01-15 12:14:33 +01:00
parent d930c2af71
commit 73a63a390d
30 changed files with 1114 additions and 103 deletions

10
.gitignore vendored
View File

@ -1,2 +1,12 @@
__pycache__/
.nox/
utility-evaluator/src/test/.DS_Store
utility-evaluator/src/test/java/.DS_Store
utility-evaluator/src/main/java/eu/nebulous/.DS_Store
utility-evaluator/src/.DS_Store
utility-evaluator/src/main/.DS_Store
utility-evaluator/src/main/java/.DS_Store
utility-evaluator/src/main/java/eu/.DS_Store
utility-evaluator/.DS_Store
.vscode/settings.json
.DS_Store

View File

@ -1,15 +0,0 @@
#
# Build stage
#
FROM docker.io/library/maven:3.9.2-eclipse-temurin-17 AS build
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package
#
# Package stage
#
FROM docker.io/library/eclipse-temurin:17-jre
COPY --from=build /home/app/target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/local/lib/demo.jar"]

View File

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,13 +0,0 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@ -1,14 +0,0 @@
package com.example.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@RequestMapping("/")
public Object root() {
return null;
}
}

View File

@ -1,14 +0,0 @@
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
//test
}
}

View File

@ -0,0 +1,12 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 http://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>my-repository-http-unblocker</id>
<mirrorOf>activeeon</mirrorOf>
<name></name>
<url>http://repository.activeeon.com/content/groups/proactive/</url>
</mirror>
</mirrors>
</settings>

View File

@ -0,0 +1,16 @@
#
# Build stage
#
FROM docker.io/library/maven:3.9.2-eclipse-temurin-17 AS build
COPY src /home/app/src
COPY local-settings.xml /home/local-settings.xml
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml -s /home/local-settings.xml clean package
#
# Package stage
#
FROM docker.io/library/eclipse-temurin:17-jre
COPY --from=build /home/app/target/utilityevaluator-0.0.1-SNAPSHOT.jar /usr/local/lib/utilityevaluator.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/local/lib/utilityevaluator.jar"]

View File

@ -0,0 +1,12 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 http://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>my-repository-http-unblocker</id>
<mirrorOf>activeeon</mirrorOf>
<name></name>
<url>http://repository.activeeon.com/content/groups/proactive/</url>
</mirror>
</mirrors>
</settings>

137
utility-evaluator/pom.xml Normal file
View File

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>eu.nebulous</groupId>
<artifactId>utilityevaluator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>utilityevaluator</name>
<description>First release of Utility Evaluator component</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
<version>3.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.ow2.proactive</groupId>
<artifactId>sal-common</artifactId>
<version>13.1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.16.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.16.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.jms/jakarta.jms-api -->
<!--<dependency>
<groupId>jakarta.jms</groupId>
<artifactId>jakarta.jms-api</artifactId>
<version>3.1.0</version>
</dependency> -->
<dependency>
<groupId>eu.nebulouscloud</groupId>
<artifactId>exn-connector-java</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven-central</id>
<url>https://repo1.maven.org/maven2/</url>
</repository>
<repository>
<id>activeeon</id>
<name>repository.activeeon</name>
<url>http://repository.activeeon.com/content/groups/proactive/</url>
</repository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,17 @@
package eu.nebulous.utilityevaluator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UtilityEvaluatorApplication {
public static void main(String[] args) {
SpringApplication.run(UtilityEvaluatorApplication.class, args);
// The application is listening to messages and sav
}
}

View File

@ -0,0 +1,38 @@
package eu.nebulous.utilityevaluator;
import org.ow2.proactive.sal.model.NodeCandidate;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Component;
import eu.nebulous.utilityevaluator.communication.activemq.message.FetchNodeCandidatesMessage;
import eu.nebulous.utilityevaluator.communication.sal.NodeCandidatesFetchingService;
import eu.nebulous.utilityevaluator.nodecandidates.NodeCandidateConverter;
import eu.nebulous.utilityevaluator.nodecandidates.NodeCandidateDTO;
import jline.internal.Log;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class UtilityEvaluatorController {
private final NodeCandidatesFetchingService nodeCandidatesService;
//this is the main method of Utiliy Evaluator. It creates a .csv file with available Node Candidates
public Optional<String> createNodeCandidatesTensor(FetchNodeCandidatesMessage message){
Log.info("Creating Node Candidates tensor...");
List<NodeCandidate> nodeCandidates = nodeCandidatesService.getNodeCandidates(message.getCloudProviders());
//convert Node Candidates, possibly also filter (in the future)
List<NodeCandidateDTO> convertedNodeCandidates = NodeCandidateConverter.convertToDtoList(nodeCandidates);
String csv = NodeCandidateConverter.convertToCsv(convertedNodeCandidates);
return Optional.of(csv);
}
}

View File

@ -0,0 +1,41 @@
package eu.nebulous.utilityevaluator;
import java.util.Optional;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import eu.nebulous.utilityevaluator.communication.activemq.message.FetchNodeCandidatesMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@RequiredArgsConstructor
public class UtilityEvaluatorListener {
// This is an old component that is going to be removed after tests
private final UtilityEvaluatorController controller;
//@JmsListener(destination = "eu.nebulouscloud.dsl.general")
//@JmsListener(destination = "TestTopic")
public void handleGeneralApplicationMessage(JSONObject message) {
// Process the received message
log.info("Received message: {}", message.toString());
FetchNodeCandidatesMessage clearedMessage = new FetchNodeCandidatesMessage(message);
log.info("Cleared message: {}", clearedMessage.toString());
Optional<String> nodeCandidatesTensor = controller.createNodeCandidatesTensor(clearedMessage);
if (nodeCandidatesTensor.isPresent()){
log.info("Tensor successfully created");
// If needed, you can also send a response back to another queue or topic
//jmsTemplate.convertAndSend("eu.nebulouslcloud.optimizer.solver.tensor", new NodeCandidatesTensorMessage(clearedMessage.getApplicationID(), nodeCandidatesTensor.get()));
log.info("Tensor was passed via ActiveMQ");
}
else {
log.error("There was an error during creating the tensor");
}
}
}

View File

@ -0,0 +1,84 @@
package eu.nebulous.utilityevaluator.communication.activemq;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
import org.springframework.jms.support.destination.DynamicDestinationResolver;
import jakarta.jms.Destination;
import jakarta.jms.JMSException;
import jakarta.jms.Session;
public class Config {
@Value("${spring.activemq.broker-url}")
String BROKER_URL;
@Value("${spring.activemq.user}")
String BROKER_USERNAME;
@Value("${spring.activemq.password}")
String BROKER_PASSWORD;
@Bean
public ActiveMQConnectionFactory connectionFactory(){
System.out.println("Connection factory being createdb for url, username and password:" + BROKER_URL + " " + BROKER_USERNAME + ", " + BROKER_PASSWORD);
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
connectionFactory.setTrustAllPackages(true);
connectionFactory.setBrokerURL(BROKER_URL);
connectionFactory.setPassword(BROKER_USERNAME);
connectionFactory.setUserName(BROKER_PASSWORD);
connectionFactory.setClientID("optimizer-utilityevaluator");
return connectionFactory;
}
@Bean
public MessageConverter messageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setObjectMapper(objectMapper());
return converter;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
@Bean
public JmsTemplate jmsTemplate(){
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(connectionFactory());
template.setMessageConverter(messageConverter());
template.setPubSubDomain(true);
template.setDestinationResolver(destinationResolver());
template.setDeliveryPersistent(true);
return template;
}
@Bean
DynamicDestinationResolver destinationResolver() {
return new DynamicDestinationResolver() {
@Override
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain) throws JMSException {
if(destinationName.endsWith("Topic")) {
pubSubDomain = true;
}
else {
pubSubDomain = false;
}
return super.resolveDestinationName(session,destinationName,pubSubDomain);
}
};
}
}

View File

@ -0,0 +1,49 @@
package eu.nebulous.utilityevaluator.communication.activemq.message;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONPointer;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class FetchNodeCandidatesMessage implements Serializable {
private static final long serialVersionUID = 1L;
private static final JSONPointer APPLICATION_ID_POINTER = new JSONPointer("/application/name");
private static final JSONPointer CLOUD_PROVIDERS_POINTER = new JSONPointer("/cloud_providers");
@NonNull
private String applicationID;
@NonNull
private Map<String,String> cloudProviders;
public FetchNodeCandidatesMessage(JSONObject generalApplicationMessage){
this.applicationID = (@NonNull String) generalApplicationMessage.query(APPLICATION_ID_POINTER);
JSONArray providersJSON = (JSONArray) generalApplicationMessage.query(CLOUD_PROVIDERS_POINTER);
Map<String,String> cloudProviders = new HashMap<String,String>();
for (final Object p : providersJSON) {
JSONObject provider = (JSONObject) p;
cloudProviders.put(provider.optString("type"), provider.optString("sal_key"));
}
this.cloudProviders = cloudProviders;
}
public FetchNodeCandidatesMessage(String appId, Map body, Map<String, Object> map){
this.applicationID = appId;
}
}

View File

@ -0,0 +1,18 @@
package eu.nebulous.utilityevaluator.communication.activemq.message;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.NonNull;
@AllArgsConstructor
public class NodeCandidatesTensorMessage implements Serializable{
private static final long serialVersionUID = 1L;
@NonNull
private String applicationID;
@NonNull
private String nodeCandidatesTensorCSV;
}

View File

@ -0,0 +1,94 @@
package eu.nebulous.utilityevaluator.communication.exnconnector;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import eu.nebulouscloud.exn.Connector;
import eu.nebulouscloud.exn.core.Consumer;
import eu.nebulouscloud.exn.handlers.ConnectorHandler;
import eu.nebulouscloud.exn.settings.StaticExnConfig;
import eu.nebulouscloud.exn.core.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
public class ExnConnector {
@Value("${spring.activemq.broker-url}")
String BROKER_URL;
@Value("${spring.activemq.broker-port}")
Integer BROKER_PORT;
@Value("${spring.activemq.user}")
String BROKER_USERNAME;
@Value("${spring.activemq.password}")
String BROKER_PASSWORD;
public static final String GENERAL_APP_CREATION_MESSAGE_TOPIC = "eu.nebulouscloud.ui.dsl.generic.>";
public final GeneralMessageHandler generalHandler;
public ExnConnector(GeneralMessageHandler handler) {
super();
this.generalHandler = handler;
init();
}
private void init() {
try {
Connector c = new Connector(
"utilityevaluator",
new MyConnectorHandler(),
List.of(),
List.of(new Consumer("ui_all", GENERAL_APP_CREATION_MESSAGE_TOPIC, generalHandler ,true,true)),
false,
false,
new StaticExnConfig(
"localhost",
5672,
BROKER_USERNAME,
BROKER_PASSWORD
)
);
c.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyConnectorHandler extends ConnectorHandler {
Logger logger = LoggerFactory.getLogger(MyConnectorHandler.class);
@Override
public void onReady(Context context) {
logger.info ("Ready start working");
//context.registerConsumer(new Consumer("ue_health","health", generalHandler, true));
/**
* We can then de-register the consumer
*/
new Thread(){
@Override
public void run() {
try {
logger.debug("Waiting for 50 s to unregister consumer");
Thread.sleep(30000);
context.unregisterConsumer("ue_health");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}

View File

@ -0,0 +1,71 @@
package eu.nebulous.utilityevaluator.communication.exnconnector;
import eu.nebulouscloud.exn.Connector;
import eu.nebulouscloud.exn.core.Consumer;
import eu.nebulouscloud.exn.core.Context;
import eu.nebulouscloud.exn.core.Handler;
import eu.nebulouscloud.exn.handlers.ConnectorHandler;
import eu.nebulouscloud.exn.settings.StaticExnConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.apache.qpid.protonj2.client.Message;
import java.util.List;
import java.util.Map;
@Component
public class ExnListener extends Handler {
private static final Logger log = LoggerFactory.getLogger(ExnListener.class);
private String topicName;
private String address;
private Connector connector;
public ExnListener(String topicName, String address, String brokerHost, int brokerPort, String username, String password) {
this.topicName = topicName;
this.address = address;
ConnectorHandler connectorHandler = new ConnectorHandler() {
@Override
public void onReady(Context context) {
log.info("Connector ready. Registering consumer for topic: {}", topicName);
// Register this handler as a consumer for the specified topic and address
context.registerConsumer(new Consumer(topicName, address, ExnListener.this, true));
}
};
// Initialize the connector with the connector handler and configuration
this.connector = new Connector("ui", connectorHandler, List.of(), List.of(), false, false,
new StaticExnConfig(brokerHost, brokerPort, username, password));
}
@Override
public void onMessage(String key, String address, Map body, Message message, Context context) {
log.info("Received message on topic {}: key={}, address={}, body={}", topicName, key, address, body);
// Implement custom message processing logic here
processMessage(key, address, body, message, context);
}
public void start() {
try {
connector.start();
log.info("ExnListener started for topic: {}", topicName);
} catch (Exception e) {
log.error("Error starting ExnListener: {}", e.getMessage());
}
}
public void stop() {
try {
connector.stop();
log.info("ExnListener stopped for topic: {}", topicName);
} catch (Exception e) {
log.error("Error stopping ExnListener: {}", e.getMessage());
}
}
protected void processMessage(String key, String address, Map body, Message message, Context context) {
// This method can be overridden in subclasses for custom message processing
}
}

View File

@ -0,0 +1,61 @@
package eu.nebulous.utilityevaluator.communication.exnconnector;
import eu.nebulous.utilityevaluator.UtilityEvaluatorController;
import eu.nebulouscloud.exn.core.Context;
import eu.nebulouscloud.exn.core.Handler;
import java.util.Map;
import org.apache.qpid.protonj2.client.Message;
import org.apache.qpid.protonj2.client.exceptions.ClientException;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class GeneralMessageHandler extends Handler {
public final UtilityEvaluatorController controller;
public GeneralMessageHandler(UtilityEvaluatorController controller){
super();
this.controller = controller;
}
@Override
public void onMessage(String key, String address, Map body, Message message, Context context) {
log.info("Received by custom handler {} => {} = {}", key,address,String.valueOf(body));
log.info("Received message: {}", message.toString());
log.info("Body={}", body.toString());
JSONObject jsonObject = new JSONObject(body);
Map<String, Object> map = jsonObject.toMap();
try {
String applicationId = message.subject();
//todo: transform the old code to get it in the right format
} catch (ClientException e) {
e.printStackTrace();
log.error(e.getMessage());
}
/*FetchNodeCandidatesMessage clearedMessage = new FetchNodeCandidatesMessage(message);
log.info("Cleared message: {}", clearedMessage.toString());
Optional<String> nodeCandidatesTensor = controller.createNodeCandidatesTensor(clearedMessage);
if (nodeCandidatesTensor.isPresent()){
log.info("Tensor successfully created");
// If needed, you can also send a response back to another queue or topic
//jmsTemplate.convertAndSend("eu.nebulouslcloud.optimizer.solver.tensor", new NodeCandidatesTensorMessage(clearedMessage.getApplicationID(), nodeCandidatesTensor.get()));
log.info("Tensor was passed via ActiveMQ");
}
else {
log.error("There was an error during creating the tensor");
}*/
}
}

View File

@ -0,0 +1,71 @@
package eu.nebulous.utilityevaluator.communication.sal;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.ow2.proactive.sal.model.NodeCandidate;
import org.ow2.proactive.sal.model.Requirement;
import org.springframework.stereotype.Component;
import eu.nebulous.utilityevaluator.communication.sal.error.ProactiveClientException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor
@Component
public class NodeCandidatesFetchingService {
private static final int NUMBER_OF_REPEATS_FOR_NODE_CANDIDATES = 120;
private static final int DELAY_BETWEEN_REQUESTS = 5000;
private final ProactiveConnector proactiveClientConnectorService;
/*public NodeCandidatesFetchingService(ProactiveClientProperties properties){
ProactiveConnector connector = new ProactiveConnector(properties);
this.proactiveClientConnectorService = connector;
}*/
//https://gitlab.ow2.org/melodic/melodic-upperware/-/tree/morphemic-rc4.0/cp_generator/src/main/java/eu/paasage/upperware/profiler/generator/communication/impl
public List<NodeCandidate> getNodeCandidates(Map<String,String> cloudProviders){
List<Requirement> providerRequirements = convertProviderRequirements(cloudProviders);
return findNodeCandidates(providerRequirements);
}
private List<Requirement> convertProviderRequirements(Map<String,String> cloudProviders){
//todo: filter based on the chosen cloud providers
return List.of();
}
private List<NodeCandidate> findNodeCandidates(List<Requirement> requirements) {
List<NodeCandidate> nodeCandidates = new LinkedList<>();
boolean isAnyAsyncNodeCandidatesProcessesInProgress = true;
int requestNo = 0;
try {
while (isAnyAsyncNodeCandidatesProcessesInProgress && (requestNo < NUMBER_OF_REPEATS_FOR_NODE_CANDIDATES)) {
log.info("Checking if nodeCandidates downlaod process is finished. Trye: {}", requestNo);
isAnyAsyncNodeCandidatesProcessesInProgress = proactiveClientConnectorService.isAnyAsyncNodeCandidatesProcessesInProgress();
Thread.sleep(DELAY_BETWEEN_REQUESTS);
requestNo++;
}
if (isAnyAsyncNodeCandidatesProcessesInProgress) {
throw new RuntimeException("NodeCandidates are not yet present inside proactive scheduler");
}
nodeCandidates = proactiveClientConnectorService.fetchNodeCandidates(requirements);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ProactiveClientException e2) {
log.error("Error message body: {}", e2.getMessage());
}
return nodeCandidates;
}
}

View File

@ -0,0 +1,27 @@
package eu.nebulous.utilityevaluator.communication.sal;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Getter
public class ProactiveClientProperties {
@Value("${spring.pa-config.rest-url}")
public String url;
@Value("${spring.pa-config.login}")
public String login;
@Value("${spring.pa-config.password}")
public String password;
public ProactiveClientProperties(@Value("${spring.pa-config.rest-url}") String url,
@Value("${spring.pa-config.login}") String login,
@Value("${spring.pa-config.password}") String password) {
this.url = url;
this.login = login;
this.password = password;
}
}

View File

@ -0,0 +1,142 @@
package eu.nebulous.utilityevaluator.communication.sal;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.nebulous.utilityevaluator.communication.sal.error.ProactiveClientException;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.logging.LogLevel;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONObject;
import org.ow2.proactive.sal.model.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import reactor.netty.ByteBufMono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.*;
@Slf4j
@Service
public class ProactiveConnector {
private static final String SESSION_HEADER = "sessionid";
private static final int RETRIES_NUMBER = 20;
private static final String PA_GATEWAY = "/pagateway";
private static final String PA_GATEWAY_CONNECT = PA_GATEWAY + "/connect";
private static final String NODECANDIDATES = "/nodecandidates";
public static final String CLOUD = "/cloud";
public static final String CLOUD_NODE_CANDIDATES_FETCH_CHECK = CLOUD + "/async";
private final HttpClient httpClient;
private String sessionId;
private final ObjectMapper objectMapper;
public ProactiveConnector(ProactiveClientProperties properties) {
log.info("Properties: login: {}, pass: {}, url: {}", properties.getLogin(), properties.getPassword(), properties.getUrl());
this.connect(properties.getLogin(), properties.getPassword(), properties.getUrl());
//sessionId = "blablabla";
this.httpClient = HttpClient.create()
.baseUrl(properties.getUrl())
.headers(headers -> headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
.headers(headers -> headers.add(SESSION_HEADER, sessionId))
.responseTimeout(Duration.of(80, ChronoUnit.SECONDS))
.wiretap("reactor.netty.http.client.HttpClient", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL, StandardCharsets.UTF_8);
this.httpClient.warmup().block();
this.objectMapper = new ObjectMapper();
this.objectMapper
.configOverride(List.class)
.setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY))
.setSetterInfo(JsonSetter.Value.forContentNulls(Nulls.AS_EMPTY));
}
public void connect(String login, String password, String schedulerUrl) {
log.info("Connecting to SAL as a service");
this.sessionId = HttpClient.create()
.headers(headers -> headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED))
.post()
.uri(schedulerUrl + PA_GATEWAY_CONNECT)
.sendForm((req, form) -> form
//.attr("username", login)
.attr("name", login)
.attr("password", password))
.responseContent()
.aggregate()
.asString()
.retry(RETRIES_NUMBER)
.block();
log.info("Connected with sessionId: {}...", sessionId.substring(0,10));
}
//nodeCandidates
public List<NodeCandidate> fetchNodeCandidates(List<Requirement> requirements) {
return httpClient.post()
.uri(NODECANDIDATES)
.send(bodyMonoPublisher(requirements))
.responseSingle((resp, bytes) -> {
if (!resp.status().equals(HttpResponseStatus.OK)) {
return bytes.asString().flatMap(body -> Mono.error(new ProactiveClientException(body)));
} else {
return bytes.asString().mapNotNull(s -> {
try {
log.info("Received message: {}", s);
return objectMapper.readValue(s, NodeCandidate[].class);
} catch (IOException e) {
log.error(e.getMessage(), e);;
return null;
}
});
}
})
.doOnError(Throwable::printStackTrace)
.blockOptional()
.map(Arrays::asList)
.orElseGet(Collections::emptyList);
}
private Mono<ByteBuf> bodyMonoPublisher(Object body) {
if ((body instanceof JSONArray) || (body instanceof JSONObject)) {
return ByteBufMono.fromString(Mono.just(body.toString()));
}
String json = null;
try {
json = objectMapper.writeValueAsString(body);
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);;
}
log.info("Sending body json: {}", json);
return ByteBufMono.fromString(Mono.just(json));
}
public Boolean isAnyAsyncNodeCandidatesProcessesInProgress() {
return httpClient.get()
.uri(CLOUD_NODE_CANDIDATES_FETCH_CHECK)
.responseSingle((resp, bytes) -> {
if (!resp.status().equals(HttpResponseStatus.OK)) {
return bytes.asString().flatMap(body -> Mono.error(new ProactiveClientException(body)));
} else {
return bytes.asString().map(Boolean::new);
}
})
.doOnError(Throwable::printStackTrace)
.block();
}
}

View File

@ -0,0 +1,18 @@
package eu.nebulous.utilityevaluator.communication.sal.error;
import reactor.netty.http.client.HttpClientResponse;
public class ProactiveClientException extends RuntimeException {
public ProactiveClientException(String message) {
super(message);
}
public ProactiveClientException(HttpClientResponse clientResponse) {
super(clientResponse.status().toString());
}
public ProactiveClientException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,64 @@
package eu.nebulous.utilityevaluator.nodecandidates;
import java.util.List;
import java.util.stream.Collectors;
import org.ow2.proactive.sal.model.NodeCandidate;
//static class that converts Node Candidates from SAL to NodeCandidatesDTO, which are then directly saved in node Candidates tensor
public class NodeCandidateConverter {
public static final String CSV_HEADER = "id;gpu;cpu;ram;location;latitude;longitude;provider;type;price\n";
public static List<NodeCandidateDTO> convertToDtoList(List<NodeCandidate> nodeCandidates) {
return nodeCandidates.stream()
.map(NodeCandidateConverter::convertToDto)
.collect(Collectors.toList());
}
private static NodeCandidateDTO convertToDto(NodeCandidate nodeCandidate) {
NodeCandidateDTO dto = new NodeCandidateDTO(
nodeCandidate.getNodeCandidateType(),
nodeCandidate.getPrice(),
nodeCandidate.getCloud().getId(),
nodeCandidate.getHardware().getCores(),
nodeCandidate.getHardware().getFpga(),
nodeCandidate.getHardware().getRam(),
nodeCandidate.getLocation().getGeoLocation().getCountry(),
nodeCandidate.getLocation().getGeoLocation().getLatitude(),
nodeCandidate.getLocation().getGeoLocation().getLongitude(),
nodeCandidate.getId()
);
return dto;
}
public static String convertToCsv(List<NodeCandidateDTO> nodeCandidates) {
// Create CSV header
String csv = CSV_HEADER;
// Append node candidates to CSV
csv += nodeCandidates.stream()
.map(nc->NodeCandidateConverter.convertNodeCandidateToCsv(nc))
.collect(Collectors.joining("\n"));
return csv;
}
private static String convertNodeCandidateToCsv(NodeCandidateDTO nodeCandidate) {
// Convert a single NodeCandidate to CSV format
return String.format("%s;%d;%d;%d;%s;%f;%f;%s;%s;%f",
nodeCandidate.getId(),
nodeCandidate.getGpu(),
nodeCandidate.getCpu(),
nodeCandidate.getRam(),
nodeCandidate.getLocation(),
nodeCandidate.getLatitude(),
nodeCandidate.getLongitude(),
nodeCandidate.getProvider(),
nodeCandidate.getType(),
nodeCandidate.getPrice());
}
}

View File

@ -0,0 +1,36 @@
package eu.nebulous.utilityevaluator.nodecandidates;
import org.ow2.proactive.sal.model.NodeCandidate;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
@AllArgsConstructor
public class NodeCandidateDTO {
@NonNull
private NodeCandidate.NodeCandidateTypeEnum type;
@NonNull
private Double price;
@NonNull
private String provider;
@NonNull
private Integer cpu;
@NonNull
private Integer gpu;
@NonNull
private Long ram;
@NonNull
private String location;
@NonNull
private Double latitude;
@NonNull
private Double longitude;
private String id;
}

View File

@ -0,0 +1,8 @@
spring.pa-config.rest-url=http://localhost:8088/sal
spring.pa-config.url=http://localhost:8080/
spring.pa-config.login=admin
spring.pa-config.password=admin
spring.activemq.broker-url=localhost
spring.activemq.broker-port=5672
spring.activemq.user=admin
spring.activemq.password=admin

View File

@ -0,0 +1,83 @@
package eu.nebulous.utilityevaluator;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.ow2.proactive.sal.model.Cloud;
import org.ow2.proactive.sal.model.CloudType;
import org.ow2.proactive.sal.model.GeoLocation;
import org.ow2.proactive.sal.model.Hardware;
import org.ow2.proactive.sal.model.NodeCandidate;
import org.ow2.proactive.sal.model.NodeCandidate.NodeCandidateTypeEnum;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.jms.core.JmsTemplate;
import eu.nebulous.utilityevaluator.communication.activemq.message.FetchNodeCandidatesMessage;
import eu.nebulous.utilityevaluator.nodecandidates.NodeCandidateConverter;
import eu.nebulous.utilityevaluator.nodecandidates.NodeCandidateDTO;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@SpringBootTest
class UtilityEvaluatorApplicationTests {
@MockBean
private JmsTemplate jmsTemplate;
//@Test
void testNodeCandidatesConverter() {
// Arrange
List<NodeCandidate> mockNodeCandidates = Collections.singletonList(createMockNodeCandidate());
Map<String,String> cloudProviders = Map.of("aws-ec2", "longsalid", "openstack", "longsalid2");
Mockito.when(jmsTemplate.receiveAndConvert("utilityEvaluatorInitialize"))
.thenReturn(new FetchNodeCandidatesMessage("appID",cloudProviders ));
// Act
List<NodeCandidateDTO> result = NodeCandidateConverter.convertToDtoList(mockNodeCandidates);
// Assert
assertFalse(result.isEmpty());
assertEquals(3.40, result.get(0).getLongitude());
assertEquals(56, result.get(0).getPrice());
// Add your assertions here to verify that the conversion is correct based on your logic
}
private NodeCandidate createMockNodeCandidate() {
// Create and return a mock NodeCandidate object
// Customize the object based on your requirements for testing
Hardware mockHardware = mock(Hardware.class);
mockHardware.setCores(10);
mockHardware.setRam(1000L);
mockHardware.setFpga("f");
Cloud mockCloud = new Cloud();
mockCloud.setId("testCloudID");
mockCloud.setCloudType(CloudType.PUBLIC);
org.ow2.proactive.sal.model.Location mockLocation = mock(org.ow2.proactive.sal.model.Location.class);
GeoLocation mockGeoLocation = new GeoLocation("Dublin", "IE", 15.40, 3.40);
mockLocation.setGeoLocation(mockGeoLocation);
when(mockLocation.getGeoLocation()).thenReturn(mockGeoLocation);
NodeCandidate nc = new NodeCandidate();
nc.setCloud(mockCloud);
nc.setHardware(mockHardware);
nc.setLocation(mockLocation);
nc.setPrice(56.0);
nc.setId("That'stestid");
nc.setNodeCandidateType(NodeCandidateTypeEnum.IAAS);
return nc;
}
}

View File

@ -8,15 +8,15 @@
- nebulous-optimiser-utility-evaluator-container-images
description: Build the container images.
files: &image_files
- ^java-spring-boot-demo/
- ^utility-evaluator/
vars: &image_vars
promote_container_image_job: nebulous-optimiser-utility-evaluator-upload-container-images
container_images:
- context: java-spring-boot-demo
- context: utility-evaluator
registry: quay.io
repository: quay.io/nebulous/optimiser-utility-evaluator-java-spring-boot-demo
repository: quay.io/nebulous/optimiser-utility-evaluator
namespace: nebulous
repo_shortname: optimiser-utility-evaluator-java-spring-boot-demo
repo_shortname: optimiser-utility-evaluator
repo_description: ""
- job:
@ -44,7 +44,7 @@
description: Run Hadolint on Dockerfile(s).
vars:
dockerfiles:
- java-spring-boot-demo/Dockerfile
- utility-evaluator/Dockerfile
- job:
name: nebulous-optimiser-utility-evaluator-helm-lint