Add docker library to image in Dockerfile

Change-Id: I471df77ab8677d6311291cf86f39c8a294c811d1
This commit is contained in:
gsavvas 2024-02-01 13:51:49 +02:00
parent fb02c5b703
commit dab29d1654
116 changed files with 1832 additions and 137 deletions

View File

@ -5,8 +5,8 @@
replicaCount: 1
image:
repository: "quay.io/nebulous/exn-middleware-java-spring-boot-demo"
pullPolicy: IfNotPresent
repository: "quay.io/nebulous/exn-middleware-exn-middleware-core"
pullPolicy: Always
# Overrides the image tag whose default is the chart appVersion.
tag: ""

View File

@ -0,0 +1,2 @@
#Mon Feb 05 14:24:01 EET 2024
gradle.version=7.5.1

Binary file not shown.

View File

@ -0,0 +1,35 @@
#Builder stage for maven
FROM docker.io/library/openjdk:11 AS builder
RUN apt-get update && \
apt-get install --no-install-recommends -y maven=3.6.3-5
#Set the working directory
WORKDIR /app
#Copy application POM
COPY pom.xml .
#Download dependencies in local repo
RUN mvn dependency:go-offline
#Copy source code
COPY src ./src
#Build the app
RUN mvn clean package
#Main stage
FROM docker.io/library/openjdk:11-jre-slim
#Set the working directory
WORKDIR /app
#Copy compiled jar from builder stage
COPY --from=builder /app/target/exn-middleware-core-0.0.1-SNAPSHOT.jar ./exn-middleware-core-0.0.1-SNAPSHOT.jar
#Copy application configuration
COPY config ./
#Run java app on container start
CMD ["java", "-jar", "exn-middleware-core-0.0.1-SNAPSHOT.jar"]

View File

@ -0,0 +1,38 @@
plugins {
id 'groovy'
id 'java-library'
id 'org.springframework.boot' version '2.7.18'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}
group 'eu.nebulouscloud.exn.middleware'
version '1.0-SNAPSHOT'
sourceCompatibility = '1.11'
repositories {
mavenCentral()
maven {
url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.codehaus.groovy:groovy-all:3.0.19'
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.7.0'
implementation group: 'org.springdoc', name: 'springdoc-openapi-groovy', version: '1.7.0'
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
implementation (group: 'eu.nebulouscloud','name':'exn-connector-java', version: '1.0-SNAPSHOT') {
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
implementation group: 'org.apache.qpid', name: 'protonj2-client', version: '1.0.0-M16'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,28 @@
logging:
level:
eu.nebulouscloud.exn.modules: TRACE
spring:
profiles: default
main:
web-application-type: none
jms:
pub-sub-domain: true
application:
exn:
config:
url: 'nebulous-nebulous-activemq'
port: 5672
username: 'admin'
password: 'admin'
sal:
protocol: 'http'
# host: 'fa84-194-219-170-2.ngrok-free.app/'
host: 'sal'
port: '8080'
api: 'sal'
username: 'admin'
password: 'admin'
jms:
topic: 'eu.nebulouscloud'

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

240
exn-middleware-core/gradlew vendored Executable file
View File

@ -0,0 +1,240 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

116
exn-middleware-core/pom.xml Normal file
View File

@ -0,0 +1,116 @@
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.nebulouscloud</groupId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>exn-middleware-core</artifactId>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.19</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-groovy</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>eu.nebulouscloud</groupId>
<artifactId>exn-connector-java</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.qpid</groupId>
<artifactId>protonj2-client</artifactId>
<version>1.0.0-M16</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- Surefire Plugin for JUnit tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<!-- Groovy plugin -->
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.6.2</version>
<executions>
<execution>
<goals>
<goal>addSources</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Spring Boot Maven plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.18</version>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
<repository>
<id>sonatype-snapshots</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,6 @@
pluginManagement {
repositories {
gradlePluginPortal()
}
}
rootProject.name = 'eu.nebulouscloud.exn.middleware.core'

View File

@ -0,0 +1,12 @@
package eu.nebulouscloud.exn.modules.sal
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
class ExnMiddlewareApplication {
static void main(String[] args) {
SpringApplication.run(ExnMiddlewareApplication, args)
}
}

View File

@ -0,0 +1,9 @@
package eu.nebulouscloud.exn.modules.sal.configuration
class AppConfig {
String url
Integer port
String username
String password
}

View File

@ -0,0 +1,20 @@
package eu.nebulouscloud.exn.modules.sal.configuration
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.client.RestTemplate
import java.time.Duration
@Configuration
class RestTemplateConf {
@Bean
RestTemplate restTemplateInit(RestTemplateBuilder builder){
builder.setReadTimeout(Duration.ofMinutes(3))
.setConnectTimeout(Duration.ofMinutes(1))
.build()
}
}

View File

@ -0,0 +1,16 @@
package eu.nebulouscloud.exn.modules.sal.configuration
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Configuration
@Configuration
@ConfigurationProperties(prefix = 'application.sal')
class SalConfiguration{
String protocol
String host
String port
String api
String username
String password
}

View File

@ -0,0 +1,68 @@
package eu.nebulouscloud.exn.modules.sal.middleware.config
import eu.nebulouscloud.exn.modules.sal.middleware.handlers.connection.EXNConnectorHandler
import eu.nebulouscloud.exn.Connector
import eu.nebulouscloud.exn.core.Consumer
import eu.nebulouscloud.exn.core.Publisher
import eu.nebulouscloud.exn.modules.sal.configuration.AppConfig
import eu.nebulouscloud.exn.modules.sal.middleware.handlers.consumer.AMQPSalMessageHandler
import eu.nebulouscloud.exn.settings.StaticExnConfig
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
@ConfigurationProperties(prefix='application.exn')
class ConfigureEXNConnector {
AppConfig config
@Autowired
AMQPSalMessageHandler amqpSalMessageHandler
@Bean
Connector configEXNConnector(){
Connector c = new Connector(
"exn.sal",
new EXNConnectorHandler(),
[
new Publisher("cloud.post","cloud.post.reply",true,false),
new Publisher("cloud.get","cloud.get.reply",true,false),
new Publisher("cloud.delete","cloud.delete.reply",true,false),
new Publisher("nodecandidate.post","nodecandidate.post.reply",true,false),
new Publisher("nodecandidate.get","nodecandidate.get.reply",true,false),
new Publisher("node.post","node.post.reply",true,false),
new Publisher("node.update","node.update.reply",true,false),
new Publisher("node.get","node.get.reply",true,false),
new Publisher("node.delete","node.delete.reply",true,false),
new Publisher("job.get","job.get.reply",true,false),
new Publisher("job.update","job.update.reply",true,false),
new Publisher("job.post","job.post.reply",true,false),
new Publisher("job.delete","job.delete.reply",true,false)
],
[
new Consumer("cloud","cloud.>", amqpSalMessageHandler,true,false),
new Consumer("nodecandidate","nodecandidate.>", amqpSalMessageHandler,true,false),
new Consumer("node","node.>", amqpSalMessageHandler,true,false),
new Consumer("job","job.>", amqpSalMessageHandler,true,false)
],
false,
false,
new StaticExnConfig(
config.url,
config.port,
config.username,
config.password
)
)
c.start()
return c
}
}

View File

@ -0,0 +1,38 @@
package eu.nebulouscloud.exn.modules.sal.middleware.consumers
import eu.nebulouscloud.exn.modules.sal.middleware.handlers.consumer.AMQPSalMessageHandler
import eu.nebulouscloud.exn.core.Consumer
import eu.nebulouscloud.exn.core.Context
import eu.nebulouscloud.exn.core.Handler
import groovy.util.logging.Slf4j
import org.apache.qpid.protonj2.client.Delivery
import org.apache.qpid.protonj2.client.Message
@Slf4j
class StringConsumer extends Consumer{
StringConsumer(String key, String address, Handler handler, boolean topic, boolean FQDN) {
super(key, address, handler, topic, FQDN)
}
@Override
protected void onDelivery(Delivery delivery, Context context){
log.debug("Overridden UI on delivery for delivery for {}",this.linkAddress)
Message message = delivery.message()
String body = this.processStringMessage(message, context)
(this.handler as AMQPSalMessageHandler).onStringMessage(
this.key,
this.address,
body,
message,
context
)
delivery.accept()
}
protected String processStringMessage(Message message, Context context){
log.debug("Processing message for{}",this.linkAddress)
return message.body() as String
}
}

View File

@ -0,0 +1,16 @@
package eu.nebulouscloud.exn.modules.sal.middleware.handlers.connection
import eu.nebulouscloud.exn.core.Context
import eu.nebulouscloud.exn.handlers.ConnectorHandler
import groovy.util.logging.Slf4j
@Slf4j
class EXNConnectorHandler extends ConnectorHandler{
@Override
void onReady(Context context){
log.info('Exn connector handler is ready')
}
}

View File

@ -0,0 +1,83 @@
package eu.nebulouscloud.exn.modules.sal.middleware.handlers.consumer
import com.fasterxml.jackson.databind.ObjectMapper
import eu.nebulouscloud.exn.modules.sal.processors.Processor
import eu.nebulouscloud.exn.core.Context
import eu.nebulouscloud.exn.core.Handler
import eu.nebulouscloud.exn.core.Publisher
import groovy.util.logging.Slf4j
import org.apache.commons.lang3.StringUtils
import org.apache.qpid.protonj2.client.Message
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
@Component
@Slf4j
public class AMQPSalMessageHandler extends Handler {
@Autowired
Map<String, Processor> processors
@Autowired
ObjectMapper mapper
@Value('${application.jms.topic}')
String baseQueue
@Override
void onMessage(String key, String address, Map body, Message message, Context context) {
log.info("Received by custom handler {} => {} = {}", key, address, String.valueOf(body))
try {
String destination = StringUtils.substringAfter(message.to(), '://') ?: message.to()
log.trace('Got destination {}', destination)
if (destination.contains('.reply')) {
return
}
def processor = destination.replaceAll(context.base + ".", "")
//Remove component from destination
processor = StringUtils.substringBefore(processor, '.')
processor = processor + "Processor"
def p = processors.containsKey(processor) ?
processors.get(processor) : processors.get('noOpProcessor')
Map response = p.process(destination, message)
Map amqpProperties =
['correlation-id': message.correlationId()?.toString(),
'reply-to' : message.replyTo()]
if (message.replyTo()) {
log.debug("Reply to Queue={} -> Correlation ID = {} ", message.replyTo(), message.correlationId())
String tempKey = message.replyTo() + message.correlationId()
Publisher tempPublisher = new Publisher(tempKey, message.replyTo(), true, true)
tempPublisher.send(response, null, amqpProperties)
context.unregisterPublisher(tempKey)
return
}
//Async reply to ".reply" topic
log.trace("Publishing default .reply with optional correlation {}", message.correlationId())
// Publisher publisher = context.getPublisher(StringUtils.substringAfter(destination,context.base+'.')) as StringPublisher
Publisher publisher = context.getPublisher(StringUtils.substringAfter(destination, context.base + '.'))
publisher.send(response, null, amqpProperties)
} catch (Exception e) {
log.error('Pre Sent caught exception', e)
}
}
}

View File

@ -0,0 +1,43 @@
package eu.nebulouscloud.exn.modules.sal.middleware.publishers
import eu.nebulouscloud.exn.core.Publisher
import groovy.util.logging.Slf4j
import org.apache.qpid.protonj2.client.Message
import org.apache.qpid.protonj2.client.Tracker
@Slf4j
class PropertiesPublisher extends Publisher{
PropertiesPublisher(String key, String address, boolean Topic, boolean FQDN) {
super(key, address, Topic, FQDN)
}
public send(Map body, Map<String,String> amqpProperties){
log.debug("{} Sending {}", this.address, body)
def message = this.prepareMessage(body)
amqpProperties.each {
String property, String value ->
if(!value){
return
}
switch (property) {
case 'reply-to':
message.replyTo(value)
break
case 'correlation-id':
message.correlationId(value)
break
default:
//this method does not work for the two above as
// it sets the application properties of the AMQP message,
// which reply and correlation are not part of in the AMQP spec
message.property(key,value)
}
}
Tracker tracker = this.link.send(message)
tracker.awaitSettlement()
}
}

View File

@ -0,0 +1,7 @@
package eu.nebulouscloud.exn.modules.sal.model.base
class Credentials {
String username
String secret
}

View File

@ -0,0 +1,12 @@
package eu.nebulouscloud.exn.modules.sal.model.cloud
import eu.nebulouscloud.exn.modules.sal.model.base.Credentials
class Cloud {
String cloudId
String cloudProviderName
String cloudType
Credentials credentials
}

View File

@ -0,0 +1,4 @@
package eu.nebulouscloud.exn.modules.sal.model.nodecandidate
class NodeAttributeRequirement implements NodeRequirement{
}

View File

@ -0,0 +1,7 @@
package eu.nebulouscloud.exn.modules.sal.model.nodecandidate
class NodeCandidateRequest {
List<NodeRequirement> nodeRequirements
}

View File

@ -0,0 +1,5 @@
package eu.nebulouscloud.exn.modules.sal.model.nodecandidate
interface NodeRequirement {
}

View File

@ -0,0 +1,4 @@
package eu.nebulouscloud.exn.modules.sal.model.nodecandidate
class NodeTypeRequirement implements NodeRequirement{
}

View File

@ -0,0 +1,91 @@
package eu.nebulouscloud.exn.modules.sal.processors
import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.commons.lang3.StringUtils
import org.apache.qpid.protonj2.client.impl.ClientMessage
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.web.client.HttpServerErrorException
/**
* If no license is here then you can whatever you like!
* and of course I am not liable
* <p>
* Created by fotis on 21/02/20.
*/
abstract class AbstractProcessor implements Processor {
Logger logger = LoggerFactory.getLogger(getClass())
@Autowired
ObjectMapper mapper
@Override
Map process(String destination, ClientMessage message) {
//Maybe move it to message property(?) and don't blend with application's payload
Map payload = message.body() as Map
Map metaData = payload.metaData as Map
String o = payload.body
Map ret = [:]
logger.debug("[{}] Processing {}", metaData, o)
String method = destination.substring(destination.lastIndexOf(".") + 1)
try {
switch (method) {
case 'get':
ret = get(metaData, o)
break;
case 'search':
ret = search(metaData, o)
break;
case 'update':
ret = update(metaData, o)
break;
case 'delete':
ret = delete(metaData, o)
break;
default:
ret = post(metaData,o)
}
} catch (HttpServerErrorException e) {
logger.error("[{} -> {}] Exception during gateway request for {}", metaData.user, method, o, e)
ret.status = HttpStatus.BAD_GATEWAY.value()
ret.body = ["key": "gateway-exception-error", "message": 'Gateway exception while handling request with reason' + StringUtils.substring(e.getMessage(),0,50)]
} catch (Exception e) {
logger.error("[{} -> {}] Exception for {}", metaData.user, method, o, e)
ret.status = HttpStatus.INTERNAL_SERVER_ERROR.value()
// ret.body = ["key": "generic-exception-error", "message": 'Generic exception while handling request for user ' + metaData.user + ' and reason:\n' + StringUtils.left(e.getMessage(),100)]
ret.body = ["key": "generic-exception-error", "message": 'Generic exception while handling request for user ' + StringUtils.substring(e.getMessage(),0,50)]
}
metaData.status = ret.status
// metaData.protocol = 'HTTP'
ret.remove('status')
ret.metaData = metaData
ret.body = mapper.writeValueAsString(ret.body)
return ret
}
Map post(Map metaData, String body) { return noop(metaData, body) }
Map search(Map metaData, String body) { return noop(metaData, body) }
Map update(Map metaData, String body) { return noop(metaData, body) }
Map get(Map metaData, String body) { return noop(metaData, body) }
Map delete(Map metaData, String body) { return noop(metaData, body) }
Map noop(Map metaData, String body) {
return ["status": HttpStatus.ACCEPTED.value(), "body": metaData.user + " { " + body + "}"]
}
}

View File

@ -0,0 +1,14 @@
package eu.nebulouscloud.exn.modules.sal.processors
import org.apache.qpid.protonj2.client.impl.ClientMessage
/**
* If no license is here then you can whatever you like!
* and of course I am not liable
*
* Created by fotis on 21/02/20.
*/
interface Processor {
Map process(String queue, ClientMessage message)
}

View File

@ -0,0 +1,112 @@
package eu.nebulouscloud.exn.modules.sal.processors.impl
import eu.nebulouscloud.exn.modules.sal.processors.AbstractProcessor
import eu.nebulouscloud.exn.modules.sal.repository.GatewayRepository
import eu.nebulouscloud.exn.modules.sal.configuration.SalConfiguration
import eu.nebulouscloud.exn.modules.sal.repository.cloud.CloudRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.stereotype.Service
@Service
class CloudProcessor extends AbstractProcessor{
@Autowired
CloudRepository cloudRepository
@Autowired
GatewayRepository gatewayRepository
@Autowired
SalConfiguration salConfiguration
@Override
Map post(Map metaData, String o){
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Registering cloud {}',metaData.user, o)
// User Credentials for connecting to ProActive Server.
// SAL is a REST interface to PWS. Get it from UI or store in middleware db?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
// Deserialization should happen from calling component e.g. UI and not the proxying one
// We just proxy the json payload, which has already been serialized by the calling component
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
headers.setContentType(MediaType.APPLICATION_JSON)
Integer response = cloudRepository.save(o,headers,Integer.class)
return [
"status": HttpStatus.OK.value(),
"body": ["success": response == 0]
]
}
@Override
Map get(Map metaData, String o) {
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Getting clouds {}',metaData.user, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
//Check jobId mentioned above
List response = cloudRepository.getAll(headers, List.class)
return [
"status": HttpStatus.OK.value(),
"body": response
]
}
@Override
Map delete(Map metaData, String o) {
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Deleting clouds {}',metaData.user, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
headers.setContentType(MediaType.APPLICATION_JSON)
//Check jobId mentioned above
Boolean response = cloudRepository.deleteByIds('remove',o,headers,Boolean.class)
return [
"status": HttpStatus.OK.value(),
"body": ["success":response]
]
}
}

View File

@ -0,0 +1,164 @@
package eu.nebulouscloud.exn.modules.sal.processors.impl
import eu.nebulouscloud.exn.modules.sal.configuration.SalConfiguration
import eu.nebulouscloud.exn.modules.sal.processors.AbstractProcessor
import eu.nebulouscloud.exn.modules.sal.repository.GatewayRepository
import eu.nebulouscloud.exn.modules.sal.repository.cloud.CloudRepository
import eu.nebulouscloud.exn.modules.sal.repository.job.JobRepository
import eu.nebulouscloud.exn.modules.sal.repository.job.deleteStrategies.IJobDeleteStrategy
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.stereotype.Service
@Service
class JobProcessor extends AbstractProcessor{
@Autowired
JobRepository jobRepository
@Autowired
GatewayRepository gatewayRepository
@Autowired
SalConfiguration salConfiguration
@Autowired
Map<String, IJobDeleteStrategy> deleteStrategies
@Override
Map post(Map metaData, String o){
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Creating job {}',metaData.user, o)
// User Credentials for connecting to ProActive Server.
// SAL is a REST interface to PWS. Get it from UI or store in middleware db?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
// Deserialization should happen from calling component e.g. UI and not the proxying one
// We just proxy the json payload, which has already been serialized by the calling component
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
headers.setContentType(MediaType.APPLICATION_JSON)
def response = jobRepository.save(o,headers,Object.class)
return [
"status": HttpStatus.OK.value(),
"body": response
]
}
@Override
Map get(Map metaData, String o) {
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Getting clouds {}',metaData.user, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
//Check jobId mentioned above
String jobId = metaData.jobId
def response
if(!jobId){
response = jobRepository.getAll(headers, List.class)
}else{
response= jobRepository.getById(jobId, headers)
}
return [
"status": HttpStatus.OK.value(),
"body": response
]
}
@Override
Map delete(Map metaData, String o) {
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
String jobId = metaData.jobId
String action = metaData.action
logger.info('{} - [{}] job {} and payload {}',metaData.user, action, jobId, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
headers.setContentType(MediaType.APPLICATION_JSON)
IJobDeleteStrategy deleteStrategy = deleteStrategies.get('job'+action.capitalize()+'Strategy')
if(!deleteStrategy){
return [
"status": HttpStatus.NOT_IMPLEMENTED.value(),
"body": ["key":"action-not-support","message":"Delete type "+ action +" is not supported"]
]
}
//Check jobId mentioned above
def response = deleteStrategy.handleDelete(jobId, o, headers)
return [
"status": HttpStatus.OK.value(),
"body": ["success":response]
]
}
//submit job
@Override
Map update(Map metaData, String o) {
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Submitting job {} with body {}',metaData.user, metaData.jobId, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
headers.setContentType(MediaType.APPLICATION_JSON)
//Check jobId mentioned above
Object response = jobRepository.save((metaData.jobId as String)+'/submit',o,headers, Object.class)
return [
"status": HttpStatus.OK.value(),
"body": response
]
}
}

View File

@ -0,0 +1,14 @@
package eu.nebulouscloud.exn.modules.sal.processors.impl
import eu.nebulouscloud.exn.modules.sal.processors.AbstractProcessor
import org.springframework.stereotype.Service
/**
* If no license is here then you can whatever you like!
* and of course I am not liable
*
* Created by fotis on 21/02/20.
*/
@Service
class NoOpProcessor extends AbstractProcessor{
}

View File

@ -0,0 +1,54 @@
package eu.nebulouscloud.exn.modules.sal.processors.impl
import eu.nebulouscloud.exn.modules.sal.processors.AbstractProcessor
import eu.nebulouscloud.exn.modules.sal.repository.GatewayRepository
import eu.nebulouscloud.exn.modules.sal.repository.node.NodeRegistrar
import eu.nebulouscloud.exn.modules.sal.repository.nodecandidate.NodeCandidateRepository
import eu.nebulouscloud.exn.modules.sal.configuration.SalConfiguration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.stereotype.Service
@Service('nodecandidateProcessor')
class NodeCandidateProcessor extends AbstractProcessor{
@Autowired
NodeCandidateRepository nodeCandidateRepository
@Autowired
GatewayRepository gatewayRepository
@Autowired
SalConfiguration salConfiguration
@Autowired
Map<String,NodeRegistrar> nodeRegistrarMap
@Override
Map get(Map metaData, String o) {
logger.info('{} - Getting node candidates {}',metaData.user, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
headers.setContentType(MediaType.APPLICATION_JSON)
//Check jobId mentioned above
List response = nodeCandidateRepository.findCandidates(o,headers,List.class)
return [
"status": HttpStatus.OK.value(),
"body": response
]
}
}

View File

@ -0,0 +1,172 @@
package eu.nebulouscloud.exn.modules.sal.processors.impl
import eu.nebulouscloud.exn.modules.sal.processors.AbstractProcessor
import eu.nebulouscloud.exn.modules.sal.repository.GatewayRepository
import eu.nebulouscloud.exn.modules.sal.repository.node.NodeRegistrar
import eu.nebulouscloud.exn.modules.sal.configuration.SalConfiguration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
@Component
class NodeProcessor extends AbstractProcessor{
@Autowired
GatewayRepository gatewayRepository
@Autowired
SalConfiguration salConfiguration
@Autowired
Map<String,NodeRegistrar> nodeRegistrarMap
@Override
Map post(Map metaData, String o){
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Registering node {}',metaData.user, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store in middleware db?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
String nodeType = metaData.type
NodeRegistrar nodeRegistrarRepository = nodeRegistrarMap.get(nodeType+'NodeRepository')
if(!nodeRegistrarRepository){
return [
"status": HttpStatus.NOT_IMPLEMENTED.value(),
"body": ["key":"type-not-support","message":"Node type "+ nodeType +"is not supported"]
]
}
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
def response = nodeRegistrarRepository.register(metaData.jobId as String, o, headers)
return [
"status": HttpStatus.OK.value(),
"body": ["success": response == 0]
]
}
@Override
Map get(Map metaData, String o) {
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Getting node for Job {}',metaData.user, metaData.jobId)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
String nodeType = metaData.type
NodeRegistrar nodeRegistrarRepository = nodeRegistrarMap.get(nodeType+'NodeRepository')
if(!nodeRegistrarRepository){
return [
"status": HttpStatus.NOT_IMPLEMENTED.value(),
"body": ["key":"type-not-support","message":"Node type "+ nodeType +"is not supported"]
]
}
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
Object response = nodeRegistrarRepository.getById(metaData.jobId as String, headers)
return [
"status": HttpStatus.OK.value(),
"body": response
]
}
@Override
Map delete(Map metaData, String o) {
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Deleting nodes for Job {}',metaData.user, metaData.jobId)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store behind the scenes ?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
String nodeType = metaData.type
NodeRegistrar nodeRegistrarRepository = nodeRegistrarMap.get(nodeType+'NodeRepository')
if(!nodeRegistrarRepository){
return [
"status": HttpStatus.NOT_IMPLEMENTED.value(),
"body": ["key":"type-not-support","message":"Node type "+ nodeType +"is not supported"]
]
}
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
Object response = nodeRegistrarRepository.deleteById(metaData.jobId as String, headers)
return [
"status": HttpStatus.OK.value(),
"body": response
]
}
@Override
Map update(Map metaData, String o){
def ret =[
"status": HttpStatus.OK.value(),
"body": {}
]
logger.info('{} - Assigning node {} to job with payload: {}',metaData.user, metaData.jobId, o)
//User Credentials for connecting to ProActive Server.
//SAL is a REST interface to PWS. Get it from UI or store in middleware db?
String sessionId = gatewayRepository.login(salConfiguration.username,salConfiguration.password)
String nodeType = metaData.type
NodeRegistrar nodeRegistrarRepository = nodeRegistrarMap.get(nodeType+'NodeRepository')
if(!nodeRegistrarRepository){
return [
"status": HttpStatus.NOT_IMPLEMENTED.value(),
"body": ["key":"type-not-support","message":"Node type "+ nodeType +"is not supported"]
]
}
HttpHeaders headers = new HttpHeaders()
headers.add('sessionid',sessionId)
def response = nodeRegistrarRepository.assign(metaData.jobId as String, o, headers)
return [
"status": HttpStatus.OK.value(),
"body": ["success": response == 0]
]
}
}

View File

@ -0,0 +1,146 @@
package eu.nebulouscloud.exn.modules.sal.repository
import com.fasterxml.jackson.databind.ObjectMapper
import eu.nebulouscloud.exn.modules.sal.configuration.SalConfiguration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.RequestEntity
import org.springframework.web.client.HttpStatusCodeException
import org.springframework.web.client.RestTemplate
abstract class AbstractSalRepository{
protected final String resource
AbstractSalRepository(String resource){
this.resource = resource
}
@Autowired
RestTemplate restTemplate
@Autowired
ObjectMapper mapper
@Autowired
SalConfiguration configuration
//POST
//For session token
protected String post(String url, Map body, HttpHeaders headers) throws HttpStatusCodeException{
HttpEntity entity = new HttpEntity(body, headers)
return restTemplate.postForEntity(baseUrl+'/'+resource+(url?'/'+url:''), entity, String.class).getBody()
}
//Not tested -> Created FOR NODES and JOBS that we dont know the payload
protected <T> T post(String url, String body, HttpHeaders headers) throws HttpStatusCodeException{
post(url, body, headers, Object.class)
}
protected Map post(String body, HttpHeaders headers) throws HttpStatusCodeException{
post(null,body,headers,Map.class)
}
protected <T> T post(String body, HttpHeaders headers, Class responseType) throws HttpStatusCodeException{
return post(null,body,headers,responseType)
}
protected <T> T post(String url, String body, HttpHeaders headers, Class responseType) throws HttpStatusCodeException{
HttpEntity entity = new HttpEntity(body, headers)
return restTemplate.postForEntity(baseUrl+'/'+resource+(url?'/'+url:''), entity, responseType).getBody() as T
}
//Delete
protected def delete(String url, HttpHeaders headers){
delete(url, null,headers, Object.class)
}
protected def delete(String url, String body, HttpHeaders headers, Class responseType) throws HttpStatusCodeException{
RequestEntity<String> entity = new RequestEntity<String>(body,headers,HttpMethod.DELETE,new URI(baseUrl+'/'+resource+(url? '/'+url:'')))
return restTemplate.exchange(entity, responseType).getBody()
}
//PUT
protected Object put(String url, String body, HttpHeaders headers) throws HttpStatusCodeException{
RequestEntity<String> entity = new RequestEntity<String>(body, headers, HttpMethod.PUT, new URI(baseUrl+'/'+resource+(url? '/'+url:'')))
return restTemplate.exchange(entity, Object.class).getBody()
}
//GET
protected <T> T get(HttpHeaders headers, Class responseType) throws HttpStatusCodeException{
get(null, headers, responseType)
}
protected <T> T get(String url, HttpHeaders headers, Class responseType) throws HttpStatusCodeException{
RequestEntity<String> entity = new RequestEntity<String>(headers, HttpMethod.GET, new URI(baseUrl+'/'+resource+(url? '/'+url:'')))
return restTemplate.exchange(entity, responseType).getBody() as T
}
def getById(String id, HttpHeaders headers){
return get(id, headers, Map.class)
}
def getAll(HttpHeaders headers){
return getAll(headers,Map.class)
}
def getAll(HttpHeaders headers, Class responseType){
return get(headers,responseType)
}
def save(String body, HttpHeaders headers){
return save(body, headers, Map.class)
}
def save(String url, String body, HttpHeaders headers){
return post(url, body,headers, Map.class)
}
def save(String body, HttpHeaders headers, Class responseType){
return post(null,body, headers, responseType)
}
def save(String url, String body, HttpHeaders headers, Class responseType){
return post(url, body, headers, responseType)
}
def update(String url, String body, HttpHeaders headers){
return put(url, body, headers)
}
String getBaseUrl(){
return "${configuration.protocol}://${configuration.host}:${configuration.port}/${configuration.api}"
// return "${configuration.protocol}://${configuration.host}/${configuration.api}"
}
def deleteByIds(String url, String body, HttpHeaders headers, Class responseType){
return delete(url,body,headers,responseType)
}
}

View File

@ -0,0 +1,31 @@
package eu.nebulouscloud.exn.modules.sal.repository
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.stereotype.Repository
import org.springframework.util.LinkedMultiValueMap
import org.springframework.util.MultiValueMap
import org.springframework.web.client.HttpClientErrorException
@Repository
class GatewayRepository extends AbstractSalRepository{
GatewayRepository() {
super('pagateway')
}
String login(String username, String password) throws HttpClientErrorException.Unauthorized{
MultiValueMap credentials = new LinkedMultiValueMap<String, String>()
credentials.add('username',username)
credentials.add('password',password)
HttpHeaders headers = new HttpHeaders()
headers.setContentType(MediaType.MULTIPART_FORM_DATA)
String sessionId = post('connect', credentials, headers)
return sessionId
}
}

View File

@ -0,0 +1,14 @@
package eu.nebulouscloud.exn.modules.sal.repository.cloud
import eu.nebulouscloud.exn.modules.sal.repository.AbstractSalRepository
import org.springframework.stereotype.Repository
@Repository
class CloudRepository extends AbstractSalRepository{
CloudRepository() {
super('clouds')
}
}

View File

@ -0,0 +1,12 @@
package eu.nebulouscloud.exn.modules.sal.repository.job
import eu.nebulouscloud.exn.modules.sal.repository.AbstractSalRepository
import org.springframework.stereotype.Repository
@Repository
class JobRepository extends AbstractSalRepository{
JobRepository() {
super('jobs')
}
}

View File

@ -0,0 +1,8 @@
package eu.nebulouscloud.exn.modules.sal.repository.job.deleteStrategies
import org.springframework.http.HttpHeaders
interface IJobDeleteStrategy {
def handleDelete(String jobId, String body, HttpHeaders headers)
}

Some files were not shown because too many files have changed in this diff Show More