diff --git a/charts/nebulous-overlay-network-manager/Chart.yaml b/charts/nebulous-overlay-network-manager/Chart.yaml
index 60a4c5f..6b8b804 100644
--- a/charts/nebulous-overlay-network-manager/Chart.yaml
+++ b/charts/nebulous-overlay-network-manager/Chart.yaml
@@ -22,3 +22,8 @@ version: 0.1.0
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "latest"
+
+dependencies:
+ - name: postgresql
+ version: 14.3.3
+ repository: https://charts.bitnami.com/bitnami
diff --git a/charts/nebulous-overlay-network-manager/templates/deployment.yaml b/charts/nebulous-overlay-network-manager/templates/deployment.yaml
index 3234152..5aac584 100644
--- a/charts/nebulous-overlay-network-manager/templates/deployment.yaml
+++ b/charts/nebulous-overlay-network-manager/templates/deployment.yaml
@@ -27,6 +27,10 @@ spec:
serviceAccountName: {{ include "nebulous-overlay-network-manager.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
+ initContainers:
+ - name: wait-for-postgresql
+ image: docker.io/bitnami/postgresql:14.3.0
+ command: ['sh', '-c', 'until pg_isready -h nebulous-overlay-network-manager-postgresql -p 5432; do echo waiting for database; sleep 2; done;']
containers:
- name: {{ .Chart.Name }}
securityContext:
@@ -34,19 +38,33 @@ spec:
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- - name: http
- containerPort: 8080
+ - name: onm-api
+ containerPort: 8082
+ protocol: TCP
+ - name: pgadmin
+ containerPort: 5050
protocol: TCP
- livenessProbe:
- httpGet:
- path: /
- port: http
- readinessProbe:
- httpGet:
- path: /
- port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
+ env:
+ - name: POSTGRES_USER
+ value: {{ .Values.postgresql.global.postgresql.auth.username }}
+ - name: POSTGRES_PASSWORD
+ value: {{ .Values.postgresql.global.postgresql.auth.password }}
+ - name: POSTGRES_DB
+ value: {{ .Values.postgresql.global.postgresql.auth.database }}
+ - name: POSTGRES_IP_FQDN
+ value: "nebulous-overlay-network-manager-postgresql"
+ - name: POSTGRES_CONNECTION_STRING
+ value: "jdbc:postgresql://nebulous-overlay-network-manager-postgresql:5432/postgres"
+ - name: WIREGUARD_NETWORK_PORTION
+ value: "{{ .Values.customEnv.WIREGUARD_NETWORK_PORTION }}"
+ - name: WIREGUARD_DEFAULT_SERVER_IP
+ value: "{{ .Values.customEnv.WIREGUARD_DEFAULT_SERVER_IP }}"
+ - name: WIREGUARD_ALLOWED_IPS
+ value: "{{ .Values.customEnv.WIREGUARD_ALLOWED_IPS }}"
+ - name: _PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR
+ value: "{{ .Values.customEnv._PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR }}"
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
diff --git a/charts/nebulous-overlay-network-manager/templates/service.yaml b/charts/nebulous-overlay-network-manager/templates/service.yaml
index 4e60fb7..dd4ebf8 100644
--- a/charts/nebulous-overlay-network-manager/templates/service.yaml
+++ b/charts/nebulous-overlay-network-manager/templates/service.yaml
@@ -7,9 +7,13 @@ metadata:
spec:
type: {{ .Values.service.type }}
ports:
- - port: {{ .Values.service.port }}
- targetPort: http
+ - port: {{ .Values.service.pgadminPort }}
+ targetPort: pgadmin
protocol: TCP
- name: http
+ name: pgadmin
+ - port: {{ .Values.service.onmApiPort }}
+ targetPort: onm-api
+ protocol: TCP
+ name: onm-api
selector:
{{- include "nebulous-overlay-network-manager.selectorLabels" . | nindent 4 }}
diff --git a/charts/nebulous-overlay-network-manager/values.yaml b/charts/nebulous-overlay-network-manager/values.yaml
index 089db9c..ef4b70f 100644
--- a/charts/nebulous-overlay-network-manager/values.yaml
+++ b/charts/nebulous-overlay-network-manager/values.yaml
@@ -5,7 +5,7 @@
replicaCount: 1
image:
- repository: "quay.io/nebulous/overlay-network-manager-java-spring-boot-demo"
+ repository: "quay.io/nebulous/overlay-network-manager"
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
@@ -39,6 +39,8 @@ securityContext: {}
service:
type: ClusterIP
port: 80
+ pgadminPort: 5050
+ onmApiPort: 8082
ingress:
enabled: false
@@ -80,3 +82,18 @@ nodeSelector: {}
tolerations: []
affinity: {}
+
+postgresql:
+ global:
+ postgresql:
+ auth:
+ postgresPassword: "nebulous"
+ username: "postgresql"
+ password: "postgresql"
+ database: "postgres"
+
+customEnv:
+ WIREGUARD_NETWORK_PORTION: "192.168.55."
+ WIREGUARD_DEFAULT_SERVER_IP: "192.168.55.1"
+ WIREGUARD_ALLOWED_IPS: "192.168.55.0/24"
+ _PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR: "/deployments/wg-bootstrap-agent-scripts"
diff --git a/java-spring-boot-demo/Dockerfile b/java-spring-boot-demo/Dockerfile
deleted file mode 100644
index 427e30e..0000000
--- a/java-spring-boot-demo/Dockerfile
+++ /dev/null
@@ -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"]
diff --git a/java-spring-boot-demo/pom.xml b/java-spring-boot-demo/pom.xml
deleted file mode 100644
index 76e0f0e..0000000
--- a/java-spring-boot-demo/pom.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.1.0
-
-
- com.example
- demo
- 0.0.1-SNAPSHOT
- demo
- Demo project for Spring Boot
-
- 17
-
-
-
- org.springframework.boot
- spring-boot-starter
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/java-spring-boot-demo/src/main/java/com/example/demo/DemoApplication.java b/java-spring-boot-demo/src/main/java/com/example/demo/DemoApplication.java
deleted file mode 100644
index 094d95b..0000000
--- a/java-spring-boot-demo/src/main/java/com/example/demo/DemoApplication.java
+++ /dev/null
@@ -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);
- }
-
-}
diff --git a/java-spring-boot-demo/src/main/java/com/example/demo/DemoController.java b/java-spring-boot-demo/src/main/java/com/example/demo/DemoController.java
deleted file mode 100644
index 61a5075..0000000
--- a/java-spring-boot-demo/src/main/java/com/example/demo/DemoController.java
+++ /dev/null
@@ -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;
- }
-
-}
diff --git a/java-spring-boot-demo/src/main/resources/application.properties b/java-spring-boot-demo/src/main/resources/application.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/java-spring-boot-demo/src/test/java/com/example/demo/DemoApplicationTests.java b/java-spring-boot-demo/src/test/java/com/example/demo/DemoApplicationTests.java
deleted file mode 100644
index eaa9969..0000000
--- a/java-spring-boot-demo/src/test/java/com/example/demo/DemoApplicationTests.java
+++ /dev/null
@@ -1,13 +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() {
- }
-
-}
diff --git a/network-manager/.env.example b/network-manager/.env.example
new file mode 100644
index 0000000..cd585e1
--- /dev/null
+++ b/network-manager/.env.example
@@ -0,0 +1,11 @@
+PC_IP_ADDRESS=
+
+POSTGRES_CONNECTION_STRING=
+POSTGRES_USER=
+POSTGRES_PASSWORD=
+
+WIREGUARD_NETWORK_PORTION=
+WIREGUARD_DEFAULT_SERVER_IP=
+WIREGUARD_ALLOWED_IPS=
+_DEV_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR=
+_PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR=
\ No newline at end of file
diff --git a/java-spring-boot-demo/.gitignore b/network-manager/.gitignore
similarity index 93%
rename from java-spring-boot-demo/.gitignore
rename to network-manager/.gitignore
index 549e00a..551797c 100644
--- a/java-spring-boot-demo/.gitignore
+++ b/network-manager/.gitignore
@@ -31,3 +31,6 @@ build/
### VS Code ###
.vscode/
+
+# Local environment
+.env
diff --git a/network-manager/.m2/settings.xml b/network-manager/.m2/settings.xml
new file mode 100644
index 0000000..8e97b73
--- /dev/null
+++ b/network-manager/.m2/settings.xml
@@ -0,0 +1,18 @@
+
+
+
+ quarkus-base-no-auth
+
+
+
+ Job-Token
+ ${CI_JOB_TOKEN}
+
+
+
+
+
+
diff --git a/network-manager/.mvn/wrapper/.gitignore b/network-manager/.mvn/wrapper/.gitignore
new file mode 100644
index 0000000..e72f5e8
--- /dev/null
+++ b/network-manager/.mvn/wrapper/.gitignore
@@ -0,0 +1 @@
+maven-wrapper.jar
diff --git a/network-manager/.mvn/wrapper/MavenWrapperDownloader.java b/network-manager/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..1708393
--- /dev/null
+++ b/network-manager/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader
+{
+ private static final String WRAPPER_VERSION = "3.1.1";
+
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL =
+ "https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/" + WRAPPER_VERSION
+ + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use instead of the
+ * default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main( String args[] )
+ {
+ System.out.println( "- Downloader started" );
+ File baseDirectory = new File( args[0] );
+ System.out.println( "- Using base directory: " + baseDirectory.getAbsolutePath() );
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File( baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH );
+ String url = DEFAULT_DOWNLOAD_URL;
+ if ( mavenWrapperPropertyFile.exists() )
+ {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try
+ {
+ mavenWrapperPropertyFileInputStream = new FileInputStream( mavenWrapperPropertyFile );
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load( mavenWrapperPropertyFileInputStream );
+ url = mavenWrapperProperties.getProperty( PROPERTY_NAME_WRAPPER_URL, url );
+ }
+ catch ( IOException e )
+ {
+ System.out.println( "- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'" );
+ }
+ finally
+ {
+ try
+ {
+ if ( mavenWrapperPropertyFileInputStream != null )
+ {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ }
+ catch ( IOException e )
+ {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println( "- Downloading from: " + url );
+
+ File outputFile = new File( baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH );
+ if ( !outputFile.getParentFile().exists() )
+ {
+ if ( !outputFile.getParentFile().mkdirs() )
+ {
+ System.out.println( "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath()
+ + "'" );
+ }
+ }
+ System.out.println( "- Downloading to: " + outputFile.getAbsolutePath() );
+ try
+ {
+ downloadFileFromURL( url, outputFile );
+ System.out.println( "Done" );
+ System.exit( 0 );
+ }
+ catch ( Throwable e )
+ {
+ System.out.println( "- Error downloading" );
+ e.printStackTrace();
+ System.exit( 1 );
+ }
+ }
+
+ private static void downloadFileFromURL( String urlString, File destination )
+ throws Exception
+ {
+ if ( System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null )
+ {
+ String username = System.getenv( "MVNW_USERNAME" );
+ char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray();
+ Authenticator.setDefault( new Authenticator()
+ {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication()
+ {
+ return new PasswordAuthentication( username, password );
+ }
+ } );
+ }
+ URL website = new URL( urlString );
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel( website.openStream() );
+ FileOutputStream fos = new FileOutputStream( destination );
+ fos.getChannel().transferFrom( rbc, 0, Long.MAX_VALUE );
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/network-manager/.mvn/wrapper/maven-wrapper.properties b/network-manager/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..61a2ef1
--- /dev/null
+++ b/network-manager/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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
+#
+# http://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.
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
diff --git a/network-manager/Dockerfile b/network-manager/Dockerfile
new file mode 100644
index 0000000..a5a4d39
--- /dev/null
+++ b/network-manager/Dockerfile
@@ -0,0 +1,43 @@
+FROM docker.io/curlimages/curl:8.5.0 AS downloader
+ARG RUN_JAVA_VERSION=1.3.5
+RUN curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /tmp/run-java.sh
+
+FROM docker.io/maven:3.9.1-eclipse-temurin-20 AS build
+
+WORKDIR /app
+COPY src ./src
+COPY wg-bootstrap-agent-scripts ./wg-bootstrap-agent-scripts
+COPY pom.xml ./
+
+RUN mvn clean package -DskipTests
+
+FROM docker.io/eclipse-temurin:20-jre-alpine
+
+ENV USER_ID=1001
+
+RUN mkdir /deployments \
+ && chown ${USER_ID} /deployments \
+ && chmod "g+rwX" /deployments \
+ && chown 1001:root /deployments
+
+COPY --from=downloader /tmp/run-java.sh /deployments/run-java.sh
+
+RUN chown ${USER_ID} /deployments/run-java.sh && chmod 540 /deployments/run-java.sh
+
+# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
+ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
+ENV JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8090"
+ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
+
+# Copy the built artifact from the maven image
+COPY --from=build /app/target/*-runner.jar /deployments/app.jar
+
+# Copy scripts from build Dockerfile step
+COPY --from=build /app/wg-bootstrap-agent-scripts /deployments/wg-bootstrap-agent-scripts
+
+EXPOSE 8080
+EXPOSE 8090
+
+USER ${USER_ID}
+
+ENTRYPOINT [ "/deployments/run-java.sh" ]
\ No newline at end of file
diff --git a/network-manager/README.md b/network-manager/README.md
new file mode 100644
index 0000000..888146a
--- /dev/null
+++ b/network-manager/README.md
@@ -0,0 +1,85 @@
+# Overlay Network Manager
+
+## Provided Services
+
+This is a template project, providing the bare minimum in order to build a Quarkus Service.
+To be more precise, it includes:
+1. Swagger UI with OpenAPI Specification
+
+## Technology Stack
+
+This project uses Quarkus, the Supersonic Subatomic Java Framework.
+
+If you want to learn more about Quarkus, please visit its website: https://quarkus.io/.
+
+Moreover, the core services used, alongside with their versions, are:
+1. Quarkus **3.2.7.Final**
+2. Java **20**
+
+## Environmental Variables
+
+There is a .env.example file containing all the appropriate information.
+
+## Swagger/OpenAPI Services
+These are accessible through the following paths:
+1. Swagger UI: http://localhost:8080/api/swagger
+2. OpenAPI Specification: http://localhost:8080/api/openapi
+
+## Running the application in dev mode
+
+You can run your application in dev mode that enables live coding using:
+```shell script
+./mvnw compile quarkus:dev
+```
+> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/.
+
+## Packaging and running the application
+
+The application can be packaged using:
+```shell script
+./mvnw package
+```
+It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
+Be aware that it’s not a _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
+
+The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`.
+
+If you want to build a _über-jar_, execute the following command:
+```shell script
+./mvnw package -Dquarkus.package.type=uber-jar
+```
+
+The application, packaged as a _über-jar_, is now runnable using `java -jar target/*-runner.jar`.
+
+## Creating a native executable
+
+You can create a native executable using:
+```shell script
+./mvnw package -Pnative
+```
+
+Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
+```shell script
+./mvnw package -Pnative -Dquarkus.native.container-build=true
+```
+
+You can then execute your native executable with: `./target/getting-started-1.0.0-SNAPSHOT-runner`
+
+If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.
+
+Run the docker image using:
+```shell script
+docker run -i --env-file .env --rm -p 8080:8080
+```
+
+## Related Guides
+
+- RESTEasy Reactive ([guide](https://quarkus.io/guides/resteasy-reactive)): A JAX-RS implementation utilizing build time processing and Vert.x. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it.
+
+## Provided Code
+
+### RESTEasy Reactive
+
+Easily start your Reactive RESTful Web Services
+
+[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources)
diff --git a/network-manager/k8s-bootstrap-agent-scripts/casbin-k8s-gatekeeper.sh b/network-manager/k8s-bootstrap-agent-scripts/casbin-k8s-gatekeeper.sh
new file mode 100644
index 0000000..7877912
--- /dev/null
+++ b/network-manager/k8s-bootstrap-agent-scripts/casbin-k8s-gatekeeper.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# Define the original and the copy paths for the kubeconfig file
+ORIGINAL_KUBECONFIG_PATH="$HOME/.kube/config"
+KUBECONFIG_COPY_PATH="$HOME/.kube/config-copy"
+
+# Copy the original kubeconfig file to a new location
+if [ -f "$ORIGINAL_KUBECONFIG_PATH" ]; then
+ cp "$ORIGINAL_KUBECONFIG_PATH" "$KUBECONFIG_COPY_PATH"
+ echo "Kubeconfig file copied to $KUBECONFIG_COPY_PATH."
+else
+ echo "Original kubeconfig file not found at $ORIGINAL_KUBECONFIG_PATH."
+ exit 1
+fi
+
+# Create the configmap from the copied kubeconfig file
+kubectl create configmap kubeconfig --from-file=config=$KUBECONFIG_COPY_PATH
+if [ $? -eq 0 ]; then
+ echo "ConfigMap created successfully."
+else
+ echo "Failed to create ConfigMap."
+ exit 1
+fi
+
+# Directory to store the YAML files
+REPO_URL="https://gitlab.ubitech.eu/nebulous/use-cases/k8s-gatekeeper/-/raw/origin/config"
+
+# Create the directory if it doesn't exist
+CONFIG_DIR=$HOME/k8s/config
+mkdir -p $CONFIG_DIR
+
+# List of configuration files to download
+CONFIG_FILES="rbac.yaml webhook_deployment.yaml webhook_internal.yaml auth.casbin.org_casbinmodels.yaml auth.casbin.org_casbinpolicies.yaml"
+
+# Download the configuration files
+for file in $CONFIG_FILES; do
+ echo "WGET file: $file"
+ wget -O "$CONFIG_DIR/$file" "$REPO_URL/$file"
+ if [ $? -ne 0 ]; then
+ echo "Failed to download $file."
+ exit 1
+ fi
+done
+
+# apply the downloaded configurations with delay
+DELAY=5
+for file in $CONFIG_FILES; do
+ kubectl apply -f "$CONFIG_DIR/$file"
+ sleep $DELAY
+done
+
+echo "All configurations applied successfully."
\ No newline at end of file
diff --git a/network-manager/k8s-bootstrap-agent-scripts/create-k8s-node.sh b/network-manager/k8s-bootstrap-agent-scripts/create-k8s-node.sh
new file mode 100644
index 0000000..e248d79
--- /dev/null
+++ b/network-manager/k8s-bootstrap-agent-scripts/create-k8s-node.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+# Capture the second argument as the hostname
+HOSTNAME=$1
+# Set the hostname
+echo "Setting hostname to '$HOSTNAME'..."
+sudo hostnamectl set-hostname "$HOSTNAME"
+
+WIREGUARD_VPN_IP=`ip a | grep wg | grep inet | awk '{print $2}' | cut -d'/' -f1`
+
+# Create k8s directory to host all appropriate files
+mkdir -p $HOME/k8s
+
+# Update Repository
+sudo DEBIAN_FRONTEND=noninteractive apt update
+
+# Install libraries
+sudo DEBIAN_FRONTEND=noninteractive apt install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
+
+# Docker Keys
+curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
+echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+
+# Update Repositories again
+sudo DEBIAN_FRONTEND=noninteractive apt update
+
+# Install Docker
+sudo DEBIAN_FRONTEND=noninteractive apt install -y docker-ce=5:20.10.22~3-0~ubuntu-jammy docker-ce-cli=5:20.10.22~3-0~ubuntu-jammy containerd.io=1.6.14-1
+sudo usermod -aG docker $USER
+sudo systemctl enable docker
+sudo systemctl start docker
+cat < /dev/null
+
+# Update Repositories
+sudo DEBIAN_FRONTEND=noninteractive apt-get update
+
+# Install K8s CLI tools
+sudo DEBIAN_FRONTEND=noninteractive apt-get install -y kubeadm=1.22.4-00 kubelet=1.22.4-00 kubectl=1.22.4-00
+sudo DEBIAN_FRONTEND=noninteractive apt-mark hold kubeadm kubelet kubectl
+echo "KUBELET_EXTRA_ARGS=--node-ip=${WIREGUARD_VPN_IP}" | sudo tee -a /etc/default/kubelet
+sudo systemctl restart kubelet
+
+# Disable Swap
+sudo swapoff -a
+sudo sed -i '/ swap / s/^/#/' /etc/fstab
+
+# Set hostname label to K8s Node
+sudo kubectl label nodes "$HOSTNAME" disktype=ssd
+
+# Install Helm Package Manager
+curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
+sudo chmod 700 get_helm.sh
+sudo $HOME/get_helm.sh
+
+echo "Configuration complete."
diff --git a/network-manager/k8s-bootstrap-agent-scripts/create-master-k8s-node.sh b/network-manager/k8s-bootstrap-agent-scripts/create-master-k8s-node.sh
new file mode 100644
index 0000000..ca9c6c6
--- /dev/null
+++ b/network-manager/k8s-bootstrap-agent-scripts/create-master-k8s-node.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+WIREGUARD_VPN_IP=`ip a | grep wg | grep inet | awk '{print $2}' | cut -d'/' -f1`
+
+# Init kubernetes
+sudo kubeadm init --apiserver-advertise-address ${WIREGUARD_VPN_IP} --service-cidr 10.96.0.0/16 --pod-network-cidr 10.244.0.0/16
+
+# Set kubeconfig file
+mkdir -p $HOME/.kube
+sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
+sudo chown $(id -u):$(id -g) $HOME/.kube/config
+
+# Add Cilium Helm Repo
+helm repo add cilium https://helm.cilium.io/
+helm repo update
+
+# Install Cilium with Wireguard parameters
+helm install cilium cilium/cilium --namespace kube-system --set encryption.enabled=true --set encryption.type=wireguard
+
+# Add KubeVela Helm repository and update
+echo "Setting up KubeVela..."
+helm repo add kubevela https://kubevelacharts.oss-cn-hangzhou.aliyuncs.com/core
+helm repo update
+helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wait
+
+# Save join command to specific path for the worker nodes to SCP
+kubeadm token create --print-join-command > $HOME/k8s-join-command.sh
\ No newline at end of file
diff --git a/network-manager/k8s-bootstrap-agent-scripts/create-worker-k8s-node.sh b/network-manager/k8s-bootstrap-agent-scripts/create-worker-k8s-node.sh
new file mode 100644
index 0000000..3ae67dd
--- /dev/null
+++ b/network-manager/k8s-bootstrap-agent-scripts/create-worker-k8s-node.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+MASTER_IP=$1
+MASTER_USERNAME=$2
+
+# Join Kubernetes Cluster
+sudo scp -o StrictHostKeyChecking=no -i $HOME/wg-private-key.key $MASTER_USERNAME@$MASTER_IP:/home/$MASTER_USERNAME/k8s-join-command.sh /home/$USER/k8s/k8s-join-command.sh
+
+sudo chmod +x $HOME/k8s/k8s-join-command.sh
+
+sudo $HOME/k8s/k8s-join-command.sh
diff --git a/network-manager/mvnw b/network-manager/mvnw
new file mode 100755
index 0000000..eaa3d30
--- /dev/null
+++ b/network-manager/mvnw
@@ -0,0 +1,316 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ 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
+ else
+ JAVACMD="`\\unset -f command; \\command -v java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/network-manager/mvnw.cmd b/network-manager/mvnw.cmd
new file mode 100644
index 0000000..abb7c32
--- /dev/null
+++ b/network-manager/mvnw.cmd
@@ -0,0 +1,188 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/network-manager/pom.xml b/network-manager/pom.xml
new file mode 100644
index 0000000..efaec7a
--- /dev/null
+++ b/network-manager/pom.xml
@@ -0,0 +1,210 @@
+
+
+ 4.0.0
+ eu.nebulous
+ network-manager
+ 1.0.0
+
+
+ 3.11.0
+ 17
+ UTF-8
+ UTF-8
+ quarkus-bom
+ io.quarkus.platform
+ 3.2.7.Final
+
+ true
+
+ 3.0.0
+
+ ${quarkus.platform.group-id}
+ ${quarkus.platform.version}
+
+ 1.18.24
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ ${quarkus.platform.artifact-id}
+ ${quarkus.platform.version}
+ pom
+ import
+
+
+ ${quarkus.qpid.jms.group-id}
+ quarkus-qpid-jms-bom
+ ${quarkus.qpid.jms.version}
+ pom
+ import
+
+
+
+
+
+ io.quarkus
+ quarkus-resteasy
+
+
+ io.quarkus
+ quarkus-resteasy-jackson
+
+
+ io.quarkus
+ quarkus-arc
+
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+ io.quarkus
+ quarkus-smallrye-openapi
+
+
+ io.quarkus
+ quarkus-smallrye-health
+
+
+
+ com.google.code.gson
+ gson
+ 2.10.1
+
+
+
+ io.quarkus
+ quarkus-config-yaml
+
+
+
+ io.quarkus
+ quarkus-hibernate-validator
+
+
+ io.quarkus
+ quarkus-hibernate-orm-panache
+
+
+
+ io.quarkus
+ quarkus-jdbc-postgresql
+
+
+
+ org.bouncycastle
+ bcprov-jdk18on
+ 1.76
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.70
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+
+ org.apache.sshd
+ sshd-core
+ 2.11.0
+
+
+ org.apache.sshd
+ sshd-common
+ 2.11.0
+
+
+ org.apache.sshd
+ sshd-scp
+ 2.11.0
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ quarkus-maven-plugin
+ ${quarkus.platform.version}
+ true
+
+
+
+ build
+ generate-code
+ generate-code-tests
+
+
+
+
+
+ maven-compiler-plugin
+ ${compiler-plugin.version}
+
+
+ -parameters
+
+
+
+
+ maven-surefire-plugin
+ ${surefire-plugin.version}
+
+
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+ maven-failsafe-plugin
+ ${surefire-plugin.version}
+
+
+
+ integration-test
+ verify
+
+
+
+ ${project.build.directory}/${project.build.finalName}-runner
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+
+
+
+
+
+ native
+
+
+ native
+
+
+
+ false
+ native
+
+
+
+
diff --git a/network-manager/src/main/java/Application.java b/network-manager/src/main/java/Application.java
new file mode 100644
index 0000000..f421b6c
--- /dev/null
+++ b/network-manager/src/main/java/Application.java
@@ -0,0 +1,31 @@
+import io.quarkus.runtime.ShutdownEvent;
+import io.quarkus.runtime.StartupEvent;
+import io.quarkus.runtime.configuration.ProfileManager;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.event.Observes;
+
+import java.time.ZoneId;
+import java.util.TimeZone;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@ApplicationScoped
+public class Application {
+
+ private static final Logger logger = Logger.getLogger(Application.class.getName());
+
+ public Application() {
+ // Empty Constructor
+ }
+
+ void onStart(@Observes StartupEvent ev) {
+ logger.info("The application is starting...");
+ logger.log(Level.INFO,"Default timezone: {0} with id {1}", new Object[]{TimeZone.getDefault().getDisplayName(), ZoneId.systemDefault()});
+ var profile = ProfileManager.getLaunchMode();
+ logger.log(Level.INFO,"Running profile: {0}", profile);
+ }
+
+ void onStop(@Observes ShutdownEvent ev) {
+ logger.info("The application is stopping...");
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/dto/ApplicationNodeDto.java b/network-manager/src/main/java/eu/nebulous/dto/ApplicationNodeDto.java
new file mode 100644
index 0000000..4108da7
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/dto/ApplicationNodeDto.java
@@ -0,0 +1,10 @@
+package eu.nebulous.dto;
+
+public record ApplicationNodeDto(
+ String publicIp,
+ String applicationUUID,
+ Boolean isMaster,
+ String sshUsername,
+ String privateKeyBase64,
+ String publicKey
+) {}
diff --git a/network-manager/src/main/java/eu/nebulous/dto/LogDto.java b/network-manager/src/main/java/eu/nebulous/dto/LogDto.java
new file mode 100644
index 0000000..8eb2411
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/dto/LogDto.java
@@ -0,0 +1,20 @@
+package eu.nebulous.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+import java.util.logging.Level;
+
+@EqualsAndHashCode(callSuper = false)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class LogDto {
+ private Date date;
+ private Level logLevel;
+ private String title;
+ private String message;
+}
diff --git a/network-manager/src/main/java/eu/nebulous/enums/StatusEnum.java b/network-manager/src/main/java/eu/nebulous/enums/StatusEnum.java
new file mode 100644
index 0000000..3911cd0
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/enums/StatusEnum.java
@@ -0,0 +1,16 @@
+package eu.nebulous.enums;
+public enum StatusEnum {
+
+ SUCCESS("Success"),
+ FAILURE("Failure");
+
+ private final String description;
+
+ StatusEnum(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/exception/BadRequestAlertException.java b/network-manager/src/main/java/eu/nebulous/exception/BadRequestAlertException.java
new file mode 100644
index 0000000..aeee323
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/exception/BadRequestAlertException.java
@@ -0,0 +1,17 @@
+package eu.nebulous.exception;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Response;
+
+import java.io.Serial;
+
+import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST;
+
+public class BadRequestAlertException extends WebApplicationException {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ public BadRequestAlertException(String message, String entityName, String errorKey) {
+ super(Response.status(BAD_REQUEST).entity(message).header("message", "error." + errorKey).header("params", entityName).build());
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/exception/InternalServerErrorException.java b/network-manager/src/main/java/eu/nebulous/exception/InternalServerErrorException.java
new file mode 100644
index 0000000..68c3a20
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/exception/InternalServerErrorException.java
@@ -0,0 +1,19 @@
+package eu.nebulous.exception;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Response;
+
+import java.io.Serial;
+
+public class InternalServerErrorException extends WebApplicationException {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ public InternalServerErrorException() {
+ this("HTTP 500 - Internal server error. Please contact site admin.");
+ }
+
+ public InternalServerErrorException(String message) {
+ super(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(message).build());
+ }
+}
\ No newline at end of file
diff --git a/network-manager/src/main/java/eu/nebulous/exception/NotFoundAlertException.java b/network-manager/src/main/java/eu/nebulous/exception/NotFoundAlertException.java
new file mode 100644
index 0000000..a70743e
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/exception/NotFoundAlertException.java
@@ -0,0 +1,19 @@
+package eu.nebulous.exception;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Response;
+
+import java.io.Serial;
+
+import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
+
+public class NotFoundAlertException extends WebApplicationException {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ public NotFoundAlertException(String entityName) {
+ super(Response.status(NOT_FOUND).entity("Entity " + entityName + "was not found")
+ .header("message", "error." + "notfound")
+ .header("params", entityName).build());
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/model/ApplicationMasterNode.java b/network-manager/src/main/java/eu/nebulous/model/ApplicationMasterNode.java
new file mode 100644
index 0000000..135468c
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/model/ApplicationMasterNode.java
@@ -0,0 +1,50 @@
+package eu.nebulous.model;
+
+import io.quarkus.hibernate.orm.panache.PanacheEntity;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+@Entity
+@EqualsAndHashCode(callSuper = false)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ApplicationMasterNode extends PanacheEntity {
+ private String uuid;
+
+ @Column(name = "publicIp")
+ private String publicIp;
+
+ @Column(name = "applicationUUID")
+ private String applicationUUID;
+
+ @Column(name = "sshUsername")
+ private String sshUsername;
+
+ @Column(length = 5000, name = "openSSLPrivateKey")
+ private String openSSLPrivateKey;
+
+ @Column(length = 1000, name = "openSSLPublicKey")
+ private String openSSLPublicKey;
+
+ @Column(name = "wireguardPrivateKey")
+ private String wireguardPrivateKey;
+
+ @Column(name = "wireguardPublicKey")
+ private String wireguardPublicKey;
+
+ @Column(name = "wireguardOverlaySubnet")
+ private String wireguardOverlaySubnet;
+
+ @Column(name = "wireguardIp")
+ private String wireguardIp;
+
+ @Column(name = "dateCreated")
+ private Date dateCreated;
+}
diff --git a/network-manager/src/main/java/eu/nebulous/model/ApplicationWorkerNode.java b/network-manager/src/main/java/eu/nebulous/model/ApplicationWorkerNode.java
new file mode 100644
index 0000000..df51d34
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/model/ApplicationWorkerNode.java
@@ -0,0 +1,48 @@
+package eu.nebulous.model;
+
+import io.quarkus.hibernate.orm.panache.PanacheEntity;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.ManyToOne;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+@Entity
+@EqualsAndHashCode(callSuper = false)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ApplicationWorkerNode extends PanacheEntity {
+ private String uuid;
+
+ @Column(name = "publicIp")
+ private String publicIp;
+
+ @Column(name = "sshUsername")
+ private String sshUsername;
+
+ @Column(name = "wireguardPrivateKey")
+ private String wireguardPrivateKey;
+
+ @Column(name = "wireguardPublicKey")
+ private String wireguardPublicKey;
+
+ @Column(length = 5000, name = "openSSLPrivateKey")
+ private String openSSLPrivateKey;
+
+ @Column(length = 1000, name = "openSSLPublicKey")
+ private String openSSLPublicKey;
+
+ @Column(name = "dateCreated")
+ private Date dateCreated;
+
+ @Column(name = "wireguardIp")
+ private String wireguardIp;
+
+ @ManyToOne
+ public ApplicationMasterNode applicationMasterNode;
+}
diff --git a/network-manager/src/main/java/eu/nebulous/repository/ApplicationMasterNodeRepository.java b/network-manager/src/main/java/eu/nebulous/repository/ApplicationMasterNodeRepository.java
new file mode 100644
index 0000000..3d1fb07
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/repository/ApplicationMasterNodeRepository.java
@@ -0,0 +1,13 @@
+package eu.nebulous.repository;
+
+import eu.nebulous.model.ApplicationMasterNode;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class ApplicationMasterNodeRepository implements PanacheRepository {
+
+ public ApplicationMasterNode findByApplicationUUID(String applicationUUID){
+ return find("applicationUUID", applicationUUID).firstResult();
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/repository/ApplicationWorkerNodeRepository.java b/network-manager/src/main/java/eu/nebulous/repository/ApplicationWorkerNodeRepository.java
new file mode 100644
index 0000000..6a20a7d
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/repository/ApplicationWorkerNodeRepository.java
@@ -0,0 +1,20 @@
+package eu.nebulous.repository;
+
+import eu.nebulous.dto.ApplicationNodeDto;
+import eu.nebulous.model.ApplicationMasterNode;
+import eu.nebulous.model.ApplicationWorkerNode;
+import io.quarkus.hibernate.orm.panache.PanacheRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+
+import java.util.List;
+
+@ApplicationScoped
+public class ApplicationWorkerNodeRepository implements PanacheRepository {
+ public List findWorkerNodesByMasterNode(ApplicationMasterNode masterNode){
+ return find("applicationMasterNode", masterNode).list();
+ }
+
+ public ApplicationWorkerNode findWorkerByPublicIp(ApplicationNodeDto applicationNodeDto){
+ return find("publicIp", applicationNodeDto.publicIp()).firstResult();
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/resource/ApiResource.java b/network-manager/src/main/java/eu/nebulous/resource/ApiResource.java
new file mode 100644
index 0000000..738360a
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/resource/ApiResource.java
@@ -0,0 +1,20 @@
+package eu.nebulous.resource;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.Path;
+
+@Singleton
+public class ApiResource {
+ private final ApplicationNodeResource applicationNodeResource;
+
+ @Inject
+ public ApiResource(ApplicationNodeResource applicationNodeResource) {
+ this.applicationNodeResource = applicationNodeResource;
+ }
+
+ @Path("/node")
+ public ApplicationNodeResource getAuthResource() {
+ return applicationNodeResource;
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/resource/ApplicationNodeResource.java b/network-manager/src/main/java/eu/nebulous/resource/ApplicationNodeResource.java
new file mode 100644
index 0000000..758fd14
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/resource/ApplicationNodeResource.java
@@ -0,0 +1,46 @@
+package eu.nebulous.resource;
+
+import eu.nebulous.dto.ApplicationNodeDto;
+import eu.nebulous.service.ApplicationNodeService;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.validation.Valid;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.eclipse.microprofile.openapi.annotations.Operation;
+import org.eclipse.microprofile.openapi.annotations.tags.Tag;
+
+@Singleton
+public class ApplicationNodeResource {
+
+ @Inject
+ ApplicationNodeService applicationNodeService;
+
+ @POST
+ @Path("/create")
+ @Tag(name = "Application Node")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Operation(summary = "Add Application Node to Application Cluster")
+ public Response addApplicationNode(@Valid ApplicationNodeDto applicationNodeDto) {
+ // Create Configuration for Application Node
+ var logs = applicationNodeService.evaluateNodeCreation(applicationNodeDto);
+
+ return Response.ok(logs).build();
+ }
+
+ @DELETE
+ @Path("/delete")
+ @Tag(name = "Application Node")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Operation(summary = "Delete Application Node From Application Cluster")
+ public Response deleteApplicationNode(@Valid ApplicationNodeDto applicationNodeDto) {
+ // Create Configuration for Application Node
+ var logs = applicationNodeService.evaluateNodeDeletion(applicationNodeDto);
+
+ return Response.ok(logs).build();
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/resource/GatewayResource.java b/network-manager/src/main/java/eu/nebulous/resource/GatewayResource.java
new file mode 100644
index 0000000..0689856
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/resource/GatewayResource.java
@@ -0,0 +1,19 @@
+package eu.nebulous.resource;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Path;
+
+@Path("/")
+public class GatewayResource {
+ private final ApiResource apiResource;
+
+ @Inject
+ public GatewayResource(ApiResource apiResource) {
+ this.apiResource = apiResource;
+ }
+
+ @Path("/api/v1")
+ public ApiResource getApiResource() {
+ return apiResource;
+ }
+}
\ No newline at end of file
diff --git a/network-manager/src/main/java/eu/nebulous/service/ApplicationNodeService.java b/network-manager/src/main/java/eu/nebulous/service/ApplicationNodeService.java
new file mode 100644
index 0000000..3db5e38
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/service/ApplicationNodeService.java
@@ -0,0 +1,289 @@
+package eu.nebulous.service;
+
+import eu.nebulous.dto.ApplicationNodeDto;
+import eu.nebulous.dto.LogDto;
+import eu.nebulous.model.ApplicationMasterNode;
+import eu.nebulous.model.ApplicationWorkerNode;
+import eu.nebulous.repository.ApplicationMasterNodeRepository;
+import eu.nebulous.repository.ApplicationWorkerNodeRepository;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.transaction.Transactional;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.Level;
+
+@ApplicationScoped
+public class ApplicationNodeService {
+ @Inject
+ ApplicationMasterNodeRepository applicationMasterNodeRepository;
+
+ @Inject
+ ApplicationWorkerNodeRepository applicationWorkerNodeRepository;
+
+ @Inject
+ WGKeyPairGeneratorService wgKeyPairGeneratorService;
+
+ @Inject
+ RemoteCodeExecutionService remoteCodeExecutionService;
+
+ @Inject
+ LogService logService;
+
+ @ConfigProperty(name = "WIREGUARD_ALLOWED_IPS")
+ String wireguardAllowedIps;
+
+ @ConfigProperty(name = "WIREGUARD_DEFAULT_SERVER_IP")
+ String wireguardDefaultServerIp;
+
+ @ConfigProperty(name = "WIREGUARD_NETWORK_PORTION")
+ String wireguardNetworkPortion;
+
+ @ConfigProperty(name = "WG_BOOTSTRAP_AGENT_SCRIPTS_DIR")
+ String wgBootstrapAgentScriptsDir;
+
+ private static final String ONM = "ONM";
+
+ private void persistApplicationMasterNode(List logList, ApplicationNodeDto applicationNodeDto, String openSSLPrivateKey, String openSSLPublicKey,
+ String wireguardPrivateKey, String wireguardPublicKey) {
+ try {
+ var applicationMasterNode = new ApplicationMasterNode();
+ applicationMasterNode.setUuid(UUID.randomUUID().toString());
+ applicationMasterNode.setPublicIp(applicationNodeDto.publicIp());
+ applicationMasterNode.setApplicationUUID(applicationNodeDto.applicationUUID());
+ applicationMasterNode.setSshUsername(applicationNodeDto.sshUsername());
+ applicationMasterNode.setDateCreated(new Date());
+ applicationMasterNode.setOpenSSLPrivateKey(openSSLPrivateKey);
+ applicationMasterNode.setOpenSSLPublicKey(openSSLPublicKey);
+ applicationMasterNode.setWireguardPrivateKey(wireguardPrivateKey);
+ applicationMasterNode.setWireguardPublicKey(wireguardPublicKey);
+ applicationMasterNode.setWireguardOverlaySubnet(wireguardAllowedIps);
+ applicationMasterNode.setWireguardIp(wireguardDefaultServerIp);
+
+ applicationMasterNodeRepository.persist(applicationMasterNode);
+
+ logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Master (" + applicationNodeDto.publicIp() +
+ "," + applicationNodeDto.applicationUUID() + ") successfully persisted to DB!");
+ } catch (Exception e) {
+ logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Master (" + applicationNodeDto.publicIp() +
+ "," + applicationNodeDto.applicationUUID() + ") failed to be persisted to DB!");
+ }
+ }
+
+ private void persistApplicationWorkerNode(List logList, ApplicationNodeDto applicationNodeDto, ApplicationMasterNode masterNode,
+ String wireguardPrivateKey, String wireguardPublicKey, String wireguardWorkerIp) {
+ try {
+ var applicationWorkerNode = new ApplicationWorkerNode();
+ applicationWorkerNode.setUuid(UUID.randomUUID().toString());
+ applicationWorkerNode.setSshUsername(applicationNodeDto.sshUsername());
+ applicationWorkerNode.setPublicIp(applicationNodeDto.publicIp());
+ applicationWorkerNode.setApplicationMasterNode(masterNode);
+ applicationWorkerNode.setDateCreated(new Date());
+ applicationWorkerNode.setWireguardPrivateKey(wireguardPrivateKey);
+ applicationWorkerNode.setWireguardPublicKey(wireguardPublicKey);
+ applicationWorkerNode.setWireguardIp(wireguardWorkerIp);
+ applicationWorkerNode.setOpenSSLPrivateKey(applicationNodeDto.privateKeyBase64());
+ applicationWorkerNode.setOpenSSLPublicKey(applicationNodeDto.publicKey());
+
+ applicationWorkerNodeRepository.persist(applicationWorkerNode);
+
+ logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Worker (" + applicationNodeDto.publicIp() +
+ "," + applicationNodeDto.applicationUUID() + ") successfully persisted to DB!");
+ } catch (Exception e) {
+ logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Worker (" + applicationNodeDto.publicIp() +
+ "," + applicationNodeDto.applicationUUID() + ") failed to be persisted to DB!");
+ }
+ }
+
+ @Transactional
+ public List evaluateNodeCreation(ApplicationNodeDto applicationNodeDto) {
+ var logList = new ArrayList();
+
+ // Create WG Key Pair Function
+ var wireguardKeyPair = wgKeyPairGeneratorService.createWireguardKeyPair(applicationNodeDto.publicIp());
+ var wireguardPrivateKey = wireguardKeyPair.get("private");
+ var wireguardPublicKey = wireguardKeyPair.get("public");
+
+ logService.log(logList, Level.INFO, ONM, "Created WG Key Pair for Application Node with Public IP: " + applicationNodeDto.publicIp());
+
+ if (applicationNodeDto.isMaster().equals(Boolean.TRUE)) {
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-create.sh ------------------------------------");
+ logService.log(logList, Level.INFO, ONM, "SCP FILE wg-server-create.sh to HOST: " + applicationNodeDto.publicIp());
+
+ remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(),
+ 22,applicationNodeDto.privateKeyBase64(),30L,
+ wgBootstrapAgentScriptsDir + "/server/wg-server-create.sh",
+ "wireguard",null);
+ logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-server-create.sh to HOST: " + applicationNodeDto.publicIp());
+
+ var permissionsCommand = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-create.sh";
+ var executeCommand = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-create.sh " + wireguardPrivateKey + " " +
+ wireguardPublicKey + " " + " " + wireguardDefaultServerIp;
+ remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(),
+ 22,30L,
+ permissionsCommand + ";" + executeCommand, null);
+ logService.log(logList, Level.INFO, ONM, "COMMAND wg-server-create.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!");
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-create.sh ------------------------------------");
+
+ // Persist to DB
+ persistApplicationMasterNode(logList, applicationNodeDto, applicationNodeDto.privateKeyBase64(), applicationNodeDto.publicKey(),
+ wireguardPrivateKey, wireguardPublicKey);
+ } else {
+ String wireguardWorkerIp = wireguardNetworkPortion + "2";
+ ApplicationMasterNode masterNode = applicationMasterNodeRepository.findByApplicationUUID(applicationNodeDto.applicationUUID());
+ if (masterNode != null) {
+ List workerNodes = applicationWorkerNodeRepository.findWorkerNodesByMasterNode(masterNode);
+
+ logService.log(logList, Level.INFO, ONM, "Worker Nodes " + workerNodes.size());
+
+ if (!workerNodes.isEmpty()) wireguardWorkerIp = wireguardNetworkPortion + (workerNodes.size() + 2);
+ var workerNodeClientName = "wg" + wireguardWorkerIp;
+
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_server.sh ------------------------------------");
+ logService.log(logList, Level.INFO, ONM, "SCP FILE wg-client-create_server.sh to HOST: " + masterNode.getPublicIp());
+
+ remoteCodeExecutionService.scpFile(masterNode.getSshUsername(),masterNode.getPublicIp(),
+ 22, masterNode.getOpenSSLPrivateKey(), 30L,
+ wgBootstrapAgentScriptsDir + "/client/wg-client-create_server.sh",
+ "wireguard",null);
+ logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-create_server.sh to HOST: " + masterNode.getPublicIp());
+ var permissionsCommandServer = "sudo chmod +x /home/" + masterNode.getSshUsername() + "/wireguard/wg-client-create_server.sh";
+ var executeCommandServer = "sudo /home/" + masterNode.getSshUsername() + "/wireguard/wg-client-create_server.sh " + workerNodeClientName + " " + wireguardPrivateKey + " " +
+ wireguardPublicKey + " " + masterNode.getSshUsername() + " " + masterNode.getWireguardPublicKey() + " " + masterNode.getPublicIp()+":"+"51820" + " " +
+ wireguardWorkerIp + " " + wireguardAllowedIps;
+ remoteCodeExecutionService.runCommand(masterNode.getSshUsername(),masterNode.getOpenSSLPrivateKey(),masterNode.getPublicIp(),
+ 22,30L,
+ permissionsCommandServer + ";" + executeCommandServer, null);
+ logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-create_server.sh for HOST " + masterNode.getPublicIp() + " COMPLETED!");
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_server.sh ------------------------------------");
+
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_client.sh ------------------------------------");
+ remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(),
+ 22,applicationNodeDto.privateKeyBase64(),30L,
+ wgBootstrapAgentScriptsDir + "/client/wg-client-create_client.sh",
+ "wireguard",null);
+ logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-create_client.sh to HOST: " + applicationNodeDto.publicIp());
+ var permissionsCommandClient = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-create_client.sh";
+ var executeCommandClient = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-create_client.sh " + applicationNodeDto.sshUsername() + " " +
+ "\"" + masterNode.getOpenSSLPrivateKey() + "\" " + masterNode.getPublicIp() + " " + workerNodeClientName + " " + masterNode.getSshUsername();
+ remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(),
+ 22,30L, permissionsCommandClient + ";" + executeCommandClient, null);
+ logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-create_client.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!");
+
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_client.sh ------------------------------------");
+
+ // Persist to DB
+ persistApplicationWorkerNode(logList, applicationNodeDto, masterNode, wireguardPrivateKey, wireguardPublicKey, wireguardWorkerIp);
+ }
+ }
+
+ return logList;
+ }
+
+ @Transactional
+ public List evaluateNodeDeletion(ApplicationNodeDto applicationNodeDto) {
+ var logList = new ArrayList();
+
+ if(applicationNodeDto.isMaster().equals(Boolean.TRUE)) {
+ ApplicationMasterNode masterNode = applicationMasterNodeRepository.findByApplicationUUID(applicationNodeDto.applicationUUID());
+ if (masterNode == null) {
+ logService.log(logList, Level.INFO, ONM, "FAILURE -> Could not find an Application Master Node with applicationUUID " +
+ applicationNodeDto.applicationUUID());
+
+ return logList;
+ }
+
+ // Check If Master has workers below him
+ List workerNodes = applicationWorkerNodeRepository.findWorkerNodesByMasterNode(masterNode);
+ if(workerNodes.isEmpty()) {
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-delete.sh ------------------------------------");
+ logService.log(logList, Level.INFO, ONM, "SCP FILE wg-server-delete.sh to HOST: " + applicationNodeDto.publicIp());
+
+ remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(),
+ 22,applicationNodeDto.privateKeyBase64(),30L,
+ wgBootstrapAgentScriptsDir + "/server/wg-server-delete.sh",
+ "wireguard",null);
+ logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-server-delete.sh to HOST: " + applicationNodeDto.publicIp());
+ var permissionsCommand = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-delete.sh";
+ var executeCommand = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-delete.sh " + applicationNodeDto.sshUsername();
+ remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(),
+ 22,30L,
+ permissionsCommand + ";" + executeCommand, null);
+ logService.log(logList, Level.INFO, ONM, "COMMAND wg-server-delete.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!");
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-delete.sh ------------------------------------");
+ deleteApplicationMasterNode(logList, masterNode);
+ } else {
+ logService.log(logList, Level.INFO, ONM, "The Application Master Node with PublicIP " + applicationNodeDto.publicIp() +
+ " and applicationUUID " + applicationNodeDto.applicationUUID() + " has " + workerNodes.size() + " worker nodes.");
+ //TODO: What happens when a request for deletion on a WG Server appears and it has workers running??
+ }
+ } else {
+ var workerNode = applicationWorkerNodeRepository.findWorkerByPublicIp(applicationNodeDto);
+ if(workerNode == null) {
+ logService.log(logList, Level.INFO, ONM, "FAILURE -> Could not find an Application Worker Node with applicationUUID " + applicationNodeDto.publicIp());
+ return logList;
+ }
+
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_client.sh ------------------------------------");
+ logService.log(logList, Level.INFO, ONM, "SCP FILE wg-client-delete_client.sh to HOST: " + applicationNodeDto.publicIp());
+ remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(),
+ 22,applicationNodeDto.privateKeyBase64(),30L,
+ wgBootstrapAgentScriptsDir + "/client/wg-client-delete_client.sh",
+ "wireguard",null);
+ logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-delete_client_script.sh to HOST: " + applicationNodeDto.publicIp());
+ var permissionsCommandClient = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-delete_client.sh";
+ var executeCommandClient = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-delete_client.sh " + applicationNodeDto.sshUsername() +
+ " " + "wg" + workerNode.getWireguardIp();
+ remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(),
+ 22,30L,
+ permissionsCommandClient + ";" + executeCommandClient, null);
+ logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-delete_client.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!");
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_client.sh ------------------------------------");
+
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_server.sh ------------------------------------");
+ logService.log(logList, Level.INFO, ONM, "SCP FILE wg-client-delete_server.sh to HOST: " + workerNode.getApplicationMasterNode().getPublicIp());
+ remoteCodeExecutionService.scpFile(workerNode.getApplicationMasterNode().getSshUsername(),workerNode.getApplicationMasterNode().getPublicIp(),
+ 22,workerNode.getApplicationMasterNode().getOpenSSLPrivateKey(),30L,
+ wgBootstrapAgentScriptsDir + "/client/wg-client-delete_server.sh",
+ "wireguard",null);
+ logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-delete_server.sh to HOST: " + workerNode.getApplicationMasterNode().getPublicIp());
+ var permissionsCommandServer = "sudo chmod +x /home/" + workerNode.getApplicationMasterNode().getSshUsername() + "/wireguard/wg-client-delete_server.sh";
+ var executeCommandServer = "sudo /home/" + workerNode.getApplicationMasterNode().getSshUsername() + "/wireguard/wg-client-delete_server.sh " + "wg" + workerNode.getWireguardIp() +
+ " " + workerNode.getWireguardPublicKey() + " " + applicationNodeDto.sshUsername();
+ remoteCodeExecutionService.runCommand(workerNode.getApplicationMasterNode().getSshUsername(),workerNode.getApplicationMasterNode().getOpenSSLPrivateKey(),
+ workerNode.getApplicationMasterNode().getPublicIp(),22,30L, permissionsCommandServer + ";" + executeCommandServer, null);
+ logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-delete_server.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!");
+ logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_server.sh ------------------------------------");
+
+ deleteApplicationWorkerNode(logList, workerNode);
+ }
+
+ return logList;
+ }
+
+ private void deleteApplicationMasterNode(List logList, ApplicationMasterNode masterNode) {
+ try {
+ applicationMasterNodeRepository.delete(masterNode);
+ logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Master (" + masterNode.getPublicIp() + ", " +
+ masterNode.getApplicationUUID() + ") successfully deleted from the DB!");
+ } catch (Exception e) {
+ logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Master (" + masterNode.getPublicIp() + ", " +
+ masterNode.getApplicationUUID() + ") failed to be deleted from the DB!");
+ }
+ }
+
+ private void deleteApplicationWorkerNode(List logList, ApplicationWorkerNode workerNode) {
+ try {
+ applicationWorkerNodeRepository.delete(workerNode);
+ logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Worker (" + workerNode.getPublicIp() + ", " +
+ workerNode.getApplicationMasterNode().getApplicationUUID() + ") successfully deleted from the DB!");
+ } catch (Exception e) {
+ logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Worker (" + workerNode.getPublicIp() + ", " +
+ workerNode.getApplicationMasterNode().getApplicationUUID() + ") failed to be deleted from the DB!");
+ }
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/service/LogService.java b/network-manager/src/main/java/eu/nebulous/service/LogService.java
new file mode 100644
index 0000000..f69c872
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/service/LogService.java
@@ -0,0 +1,24 @@
+package eu.nebulous.service;
+
+import eu.nebulous.dto.LogDto;
+import jakarta.enterprise.context.ApplicationScoped;
+
+import java.util.Date;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@ApplicationScoped
+public class LogService {
+ private static final Logger logger = Logger.getLogger(LogService.class.getName());
+
+ public void log(List logList, Level logLevel, String title, String message) {
+ var date = new Date();
+
+ // Add log events to logList
+ logList.add(new LogDto(date, logLevel, title, message));
+
+ // Log events
+ logger.log(logLevel, "{0}: {1}", new Object[]{date, message});
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/service/RemoteCodeExecutionService.java b/network-manager/src/main/java/eu/nebulous/service/RemoteCodeExecutionService.java
new file mode 100644
index 0000000..ce4c778
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/service/RemoteCodeExecutionService.java
@@ -0,0 +1,135 @@
+package eu.nebulous.service;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.channel.ClientChannelEvent;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.scp.client.ScpClientCreator;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@ApplicationScoped
+public class RemoteCodeExecutionService {
+
+ private static final Logger logger = Logger.getLogger(RemoteCodeExecutionService.class.getName());
+
+ public void runCommand(String username, String privateKeyBase64, String host, int port,
+ long defaultTimeoutSeconds, String command, String password) {
+
+ File privateKeyFile = createTmpFile(privateKeyBase64);
+
+ var client = SshClient.setUpDefaultClient();
+ client.start();
+
+ try (var session = client.connect(username, host, port)
+ .verify(defaultTimeoutSeconds, TimeUnit.SECONDS).getSession()) {
+
+ if (password != null) {
+ session.addPasswordIdentity(password);
+ } else {
+ var fileKeyPairProvider = new FileKeyPairProvider();
+ fileKeyPairProvider.setPaths(Collections.singleton(Paths.get(privateKeyFile.getAbsolutePath())));
+ var key = fileKeyPairProvider.loadKeys(null).iterator().next();
+
+ session.addPublicKeyIdentity(key);
+ }
+
+ session.auth().verify(defaultTimeoutSeconds, TimeUnit.SECONDS); // Timeout
+
+ try (var responseStream = new ByteArrayOutputStream();
+ var channel = session.createExecChannel(command)) {
+ channel.setOut(responseStream);
+
+ try {
+ channel.open().verify(defaultTimeoutSeconds, TimeUnit.SECONDS);
+ try (var pipedIn = channel.getInvertedIn()) {
+ pipedIn.write(command.getBytes());
+ pipedIn.flush();
+ }
+
+ channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED),
+ TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds));
+ var responseString = responseStream.toString();
+
+ logger.log(Level.INFO, "Response: {0}", new Object[]{responseString});
+ } finally {
+ channel.close(false);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ client.stop();
+ privateKeyFile.delete();
+ }
+ }
+
+ public void scpFile(String username, String host, int port, String privateKeyBase64, long defaultTimeoutSeconds,
+ String localFilePath, String remoteTargetFolder, String password) {
+
+ File privateKeyFile = createTmpFile(privateKeyBase64);
+
+ var client = SshClient.setUpDefaultClient();
+ client.start();
+
+ try (var session = client.connect(username, host, port)
+ .verify(defaultTimeoutSeconds, TimeUnit.SECONDS).getSession()) {
+
+ if (password != null) {
+ session.addPasswordIdentity(password);
+ } else {
+ var fileKeyPairProvider = new FileKeyPairProvider();
+ fileKeyPairProvider.setPaths(Collections.singleton(Paths.get(privateKeyFile.getAbsolutePath())));
+ var key = fileKeyPairProvider.loadKeys(null).iterator().next();
+
+ session.addPublicKeyIdentity(key);
+ }
+
+ session.auth().verify(defaultTimeoutSeconds, TimeUnit.SECONDS);
+
+ var creator = ScpClientCreator.instance();
+ var scpClient = creator.createScpClient(session);
+
+ // To SCP a file to the remote system
+ scpClient.upload(localFilePath, "/home/" + username + "/" + remoteTargetFolder);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ client.stop();
+ privateKeyFile.delete();
+ }
+ }
+
+ private File createTmpFile(String privateKey) {
+ try {
+ // Create temp file.
+ var temp = File.createTempFile("originPK" + UUID.randomUUID(), ".txt");
+
+ // Write to temp file
+ var out = new BufferedWriter(new FileWriter(temp));
+ var decodedString = new String(Base64.getMimeDecoder().decode(privateKey.getBytes()), StandardCharsets.UTF_8);
+
+ out.write(decodedString);
+ out.close();
+
+ return temp;
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "{0} -> Problem creating tmp file for Origin Private Key File", new Object[]{new Date()});
+ return null;
+ }
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/service/SSHKeyPairGeneratorService.java b/network-manager/src/main/java/eu/nebulous/service/SSHKeyPairGeneratorService.java
new file mode 100644
index 0000000..b3aa867
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/service/SSHKeyPairGeneratorService.java
@@ -0,0 +1,82 @@
+package eu.nebulous.service;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.security.Key;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Base64;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@ApplicationScoped
+public class SSHKeyPairGeneratorService {
+
+ private static final Logger logger = Logger.getLogger(SSHKeyPairGeneratorService.class.getName());
+
+ public Map createOpenSSL(String publicIp) {
+ var openSSLKeyPairHashMap = new HashMap();
+ try {
+ Security.addProvider(new BouncyCastleProvider());
+
+ // Generate the RSA Key Pair
+ var keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(2048);
+ var pair = keyGen.generateKeyPair();
+
+ var privateKeyString = convertKeyToString(pair.getPrivate());
+ var privateKeyBase64String = Base64.getEncoder().encodeToString(privateKeyString.getBytes());
+
+ openSSLKeyPairHashMap.put("private", privateKeyBase64String);
+ // Output private key
+ logger.log(Level.INFO, "{0}: SUCCESS -> OpenSSL Private Key Base64 for {1} just created: {2}",
+ new Object[]{new Date(), publicIp, privateKeyBase64String});
+
+ // Convert public key to SSH format
+ var sshPublicKey = convertPublicKeyToSSHFormat(pair.getPublic());
+ openSSLKeyPairHashMap.put("public", sshPublicKey + " wg-public-key");
+
+ logger.log(Level.INFO, "{0}: SUCCESS -> OpenSSL Public Key (SSH Format) for {1} just created: {2} wg-public-key",
+ new Object[]{new Date(), publicIp, sshPublicKey});
+
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "{0}: FAILURE -> Error generating OpenSSL Key Pair for {1}",
+ new Object[]{new Date(), publicIp});
+ }
+
+ return openSSLKeyPairHashMap;
+ }
+
+ private static String convertKeyToString(Key key) throws IOException {
+ var writer = new StringWriter();
+ try (var pemWriter = new JcaPEMWriter(writer)) {
+ pemWriter.writeObject(key);
+ }
+ return writer.toString();
+ }
+
+ private static String convertPublicKeyToSSHFormat(PublicKey publicKey) throws IOException {
+ var rsaPublicKey = (RSAPublicKey) publicKey;
+ var byteOs = new ByteArrayOutputStream();
+ var dos = new DataOutputStream(byteOs);
+ dos.writeInt("ssh-rsa".getBytes().length);
+ dos.write("ssh-rsa".getBytes());
+ dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length);
+ dos.write(rsaPublicKey.getPublicExponent().toByteArray());
+ dos.writeInt(rsaPublicKey.getModulus().toByteArray().length);
+ dos.write(rsaPublicKey.getModulus().toByteArray());
+ var publicKeyEncoded = new String(Base64.getEncoder().encode(byteOs.toByteArray()));
+ return "ssh-rsa " + publicKeyEncoded;
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/service/WGKeyPairGeneratorService.java b/network-manager/src/main/java/eu/nebulous/service/WGKeyPairGeneratorService.java
new file mode 100644
index 0000000..cfe5926
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/service/WGKeyPairGeneratorService.java
@@ -0,0 +1,50 @@
+package eu.nebulous.service;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import org.bouncycastle.crypto.generators.X25519KeyPairGenerator;
+import org.bouncycastle.crypto.params.X25519KeyGenerationParameters;
+import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
+import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
+import org.bouncycastle.util.encoders.Base64;
+
+import java.security.SecureRandom;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@ApplicationScoped
+public class WGKeyPairGeneratorService {
+
+ private static final Logger logger = Logger.getLogger(WGKeyPairGeneratorService.class.getName());
+
+ public Map createWireguardKeyPair(String publicIp) {
+ var wireguardKeyPairHashMap = new HashMap();
+ // Initialize key generator
+ var keyPairGenerator = new X25519KeyPairGenerator();
+ keyPairGenerator.init(new X25519KeyGenerationParameters(new SecureRandom()));
+
+ // Generate key pair
+ var keyPair = keyPairGenerator.generateKeyPair();
+
+ // Extract private and public keys
+ var privateKey = (X25519PrivateKeyParameters) keyPair.getPrivate();
+ var publicKey = (X25519PublicKeyParameters) keyPair.getPublic();
+
+ // Encode keys to Base64
+ var privateKeyBase64 = Base64.toBase64String(privateKey.getEncoded());
+ var publicKeyBase64 = Base64.toBase64String(publicKey.getEncoded());
+
+ wireguardKeyPairHashMap.put("private", privateKeyBase64);
+ wireguardKeyPairHashMap.put("public", publicKeyBase64);
+
+ // Output the keys
+ logger.log(Level.INFO, "{0}: SUCCESS -> Private Key for {1} just created: {2}",
+ new Object[]{new Date(), publicIp, privateKeyBase64});
+ logger.log(Level.INFO, "{0}: SUCCESS -> Public Key for {1} just created: {2}",
+ new Object[]{new Date(), publicIp, publicKeyBase64});
+
+ return wireguardKeyPairHashMap;
+ }
+}
diff --git a/network-manager/src/main/java/eu/nebulous/util/Util.java b/network-manager/src/main/java/eu/nebulous/util/Util.java
new file mode 100644
index 0000000..b237d61
--- /dev/null
+++ b/network-manager/src/main/java/eu/nebulous/util/Util.java
@@ -0,0 +1,26 @@
+package eu.nebulous.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import eu.nebulous.exception.NotFoundAlertException;
+import jakarta.enterprise.context.ApplicationScoped;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+@ApplicationScoped
+public class Util {
+ public String exceptionResponse(Exception e){
+ var errors = new StringWriter();
+ e.printStackTrace(new PrintWriter(errors));
+ return errors.toString();
+ }
+
+ public String toString(Object obj) {
+ try {
+ return new ObjectMapper().writeValueAsString(obj);
+ } catch (JsonProcessingException e) {
+ throw new NotFoundAlertException(e.toString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/network-manager/src/main/resources/application.yml b/network-manager/src/main/resources/application.yml
new file mode 100644
index 0000000..0cc299b
--- /dev/null
+++ b/network-manager/src/main/resources/application.yml
@@ -0,0 +1,39 @@
+mp:
+ openapi:
+ extensions:
+ smallrye:
+ info:
+ title: 'API Specification'
+ version: '1.0'
+ description: 'Exposed REST Services in order to talk with the world'
+ name: 'NebulOus Overlay Network Manager'
+
+quarkus:
+ datasource:
+ db-kind: postgresql
+ jdbc:
+ url: ${POSTGRES_CONNECTION_STRING}
+ username: ${POSTGRES_USER}
+ password: ${POSTGRES_PASSWORD}
+
+ hibernate-orm:
+ database:
+ generation: update
+
+ smallrye-openapi:
+ path: '/api/openapi'
+ security-scheme: 'jwt'
+ security-scheme-name: 'Swagger Authentication'
+ security-scheme-description: 'User Authentication through Keycloak'
+
+ swagger-ui:
+ title: 'API Documentation'
+ theme: material
+ footer: © 2024
+ always-include: true
+ path: '/api/swagger'
+
+"%prod":
+ quarkus:
+ package:
+ type: uber-jar
diff --git a/network-manager/wg-bootstrap-agent-scripts/client/README.md b/network-manager/wg-bootstrap-agent-scripts/client/README.md
new file mode 100644
index 0000000..37bb078
--- /dev/null
+++ b/network-manager/wg-bootstrap-agent-scripts/client/README.md
@@ -0,0 +1,7 @@
+# Create Client
+
+* Server Name: wg0
+* Client Name: $CLIENT_NAME
+* Wireguard Client Directory: /etc/wireguard/clients/$CLIENT_NAME
+* Client Conf: /etc/wireguard/clients/$CLIENT_NAME/$CLIENT_NAME.conf
+* Server Conf: /etc/wireguard/wg0.conf
diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_client.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_client.sh
new file mode 100644
index 0000000..0f3a3f8
--- /dev/null
+++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_client.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# Check if sufficient arguments are provided
+if [ "$#" -ne 5 ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# Script parameter
+WORKER_SSH_USERNAME="$1"
+OPENSSL_PRIVATE_KEY="$2"
+SERVER_IP="$3"
+CLIENT_NAME="$4"
+MASTER_SSH_USERNAME="$5"
+
+# Update Package Repository. Upgrade and Autoremove Packages
+sudo DEBIAN_FRONTEND=noninteractive apt-get -y update
+sudo DEBIAN_FRONTEND=noninteractive apt-get -y upgrade
+sudo DEBIAN_FRONTEND=noninteractive apt-get -y autoremove
+
+
+# Step 1: Install WireGuard
+if ! command -v wg > /dev/null; then
+ sudo DEBIAN_FRONTEND=noninteractive apt install -y wireguard
+ sudo DEBIAN_FRONTEND=noninteractive apt install -y resolvconf
+fi
+
+# Step 2: Base64 Decode the OpenSSH Private Key file
+echo $OPENSSL_PRIVATE_KEY | base64 -d --ignore-garbage > /home/$WORKER_SSH_USERNAME/wg-private-key.key
+chmod 400 /home/$WORKER_SSH_USERNAME/wg-private-key.key
+
+# Step 3: Secure Copy to WG Server to get your conf file
+scp -o StrictHostKeyChecking=no -i /home/$WORKER_SSH_USERNAME/wg-private-key.key $MASTER_SSH_USERNAME@$SERVER_IP:/home/$MASTER_SSH_USERNAME/wireguard/clients/$CLIENT_NAME/$CLIENT_NAME.conf /home/$WORKER_SSH_USERNAME/wireguard
+sudo cp /home/$WORKER_SSH_USERNAME/wireguard/$CLIENT_NAME.conf /etc/wireguard/$CLIENT_NAME.conf
+
+# Step 4: Enable and Start WireGuard Client Interface
+sudo systemctl enable wg-quick@$CLIENT_NAME
+sudo systemctl start wg-quick@$CLIENT_NAME
+
+echo "WireGuard client configured and started for $CLIENT_NAME"
diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_server.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_server.sh
new file mode 100644
index 0000000..1d34081
--- /dev/null
+++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_server.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# Check if sufficient arguments are provided
+if [ "$#" -ne 8 ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# Script parameters
+SERVER_NAME="wg0"
+CLIENT_NAME="$1"
+WG_CLIENT_PRIVATE_KEY="$2"
+WG_CLIENT_PUBLIC_KEY="$3"
+SSH_USERNAME="$4"
+SERVER_PUBLIC_KEY="$5"
+SERVER_IP_PORT="$6"
+CLIENT_VPN_IP="$7"
+ALLOWED_IPS="$8"
+WG_DIR="/etc/wireguard/clients/$CLIENT_NAME"
+CLIENT_CONF="$WG_DIR/${CLIENT_NAME}.conf"
+SERVER_CONF="/etc/wireguard/${SERVER_NAME}.conf"
+
+# Step 1: Install WireGuard (if not already installed)
+if ! command -v wg > /dev/null; then
+ sudo DEBIAN_FRONTEND=noninteractive apt install -y wireguard
+fi
+
+# Step 2: Create client directory
+sudo mkdir -p "$WG_DIR"
+mkdir -p /home/$SSH_USERNAME/wireguard/clients/$CLIENT_NAME
+
+# Step 3: Generate Client Keys
+sudo echo $WG_CLIENT_PRIVATE_KEY > "$WG_DIR/${CLIENT_NAME}_privatekey"
+sudo echo $WG_CLIENT_PUBLIC_KEY > "$WG_DIR/${CLIENT_NAME}_publickey"
+client_private_key=$(sudo cat "$WG_DIR/${CLIENT_NAME}_privatekey")
+client_public_key=$(sudo cat "$WG_DIR/${CLIENT_NAME}_publickey")
+
+# Step 4: Configure WireGuard Client
+sudo bash -c "cat > $CLIENT_CONF <> $SERVER_CONF"
+
+# Step 6: Restart WireGuard to apply changes
+sudo systemctl restart wg-quick@${SERVER_NAME}
+
+echo "Client configuration for $CLIENT_NAME created and added to server config."
+echo "Transfer the client configuration to your client machine. Example command:"
+echo "scp $CLIENT_CONF user@client-ip:/path/to/destination"
diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_client.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_client.sh
new file mode 100644
index 0000000..346944d
--- /dev/null
+++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_client.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# Check if sufficient arguments are provided
+if [ "$#" -ne 2 ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# Script parameter
+SSH_USERNAME="$1"
+WG_INTERFACE_NAME="$2"
+
+# Step 1: Stop and Disable WireGuard Interface
+sudo systemctl stop wg-quick@$WG_INTERFACE_NAME
+sudo systemctl disable wg-quick@$WG_INTERFACE_NAME
+
+# Step 2: Remove Wireguard packages
+sudo apt-get remove --purge -y wireguard
+sudo apt-get autoremove -y
+
+echo "Wireguard packages have been removed."
+
+# Step 3: Remove Wireguard related directories
+sudo rm -rf /etc/wireguard
+sudo rm -rf /home/$SSH_USERNAME/wireguard
+
+echo "WireGuard configuration files removed."
+
+# Step 4: Remove WG OpenSSL Private Key
+sudo rm -rf /home/$SSH_USERNAME/wg-private-key.key
+
+# Step 5: Remove OpenSSL Public Key
+sed -i '/wireguard-pub/d' /home/$SSH_USERNAME/.ssh/authorized_keys
+
+echo "WireGuard client $WG_INTERFACE_NAME has been stopped and disabled."
diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_server.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_server.sh
new file mode 100644
index 0000000..82edaa8
--- /dev/null
+++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_server.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Check if the client public key is provided
+if [ "$#" -ne 3 ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# Script parameter
+SERVER_NAME="wg0"
+CLIENT_NAME="$1"
+CLIENT_PUBLIC_KEY="$2"
+SSH_USERNAME="$3"
+
+# Step 1: Remove the client configuration from the server
+sudo wg set ${SERVER_NAME} peer ${CLIENT_PUBLIC_KEY} remove
+
+# Step 2: Remove the client config file
+sudo rm -rf /etc/wireguard/clients/${CLIENT_NAME}
+sudo rm -rf /home/$SSH_USERNAME/wireguard/clients/${CLIENT_NAME}
+
+# Step 3: Restart WireGuard to apply changes
+sudo systemctl restart wg-quick@${SERVER_NAME}
+
+echo "Client with public key $CLIENT_PUBLIC_KEY has been removed from the server configuration."
diff --git a/network-manager/wg-bootstrap-agent-scripts/nm-bootstrap-script.sh b/network-manager/wg-bootstrap-agent-scripts/nm-bootstrap-script.sh
new file mode 100755
index 0000000..fb3ffea
--- /dev/null
+++ b/network-manager/wg-bootstrap-agent-scripts/nm-bootstrap-script.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+# "CREATE" or "DELETE" Overlay Node
+ACTION=$1
+# Define Application Node Type ("MASTER","WORKER")
+NODE_TYPE=$2
+# Application UUID
+APPLICATION_UUID=$3
+# Overlay Network Manager Public IP
+ONM_IP=$4
+
+# Get the public IP
+public_ip=$(curl -s http://httpbin.org/ip | grep -oP '(?<="origin": ")[^"]*')
+
+# Get the Application UUID from the environment variable
+application_uuid=$APPLICATION_UUID
+
+# Get the currently logged in user (assuming single user login)
+logged_in_user=$(whoami)
+
+# Get the isMaster variable from the environment variable
+if [ "$NODE_TYPE" == "MASTER" ]; then
+ IS_MASTER="true";
+elif [ "$NODE_TYPE" == "WORKER" ]; then
+ IS_MASTER="false"
+fi
+
+# Check if string1 is equal to string2
+if [ "$ACTION" == "CREATE" ]; then
+ echo "Creating OpenSSH Public/Private Key Pair..."
+ # Create Wireguard Folder to accept the wireguard scripts
+ mkdir -p /home/${logged_in_user}/wireguard
+
+ # Create OpenSSH Public/Private Key files
+ ssh-keygen -C wireguard-pub -t rsa -b 4096 -f /home/${logged_in_user}/wireguard/wireguard -N ""
+
+ cat /home/${logged_in_user}/wireguard/wireguard.pub >> /home/${logged_in_user}/.ssh/authorized_keys
+fi
+
+PRIVATE_KEY_FILE=$(cat /home/${logged_in_user}/wireguard/wireguard | base64 | tr '\n' ' ')
+
+PAYLOAD=$(cat < "
+ exit 1
+fi
+
+# Script parameters
+WG_SERVER_PRIVATE_KEY="$1"
+WG_SERVER_PUBLIC_KEY="$2"
+WG_INTERFACE="wg0"
+SERVER_IP="$3"
+LISTEN_PORT="51820"
+WG_DIR="/etc/wireguard"
+SERVER_KEYS_DIR="$WG_DIR/server_keys"
+SERVER_CONF="$WG_DIR/$WG_INTERFACE.conf"
+
+# Update Package Repository. Upgrade and Autoremove Packages
+sudo DEBIAN_FRONTEND=noninteractive apt-get -y update
+sudo DEBIAN_FRONTEND=noninteractive apt-get -y upgrade
+sudo DEBIAN_FRONTEND=noninteractive apt-get -y autoremove
+
+# Step 1: Install WireGuard package
+if ! command -v wg > /dev/null; then
+ sudo DEBIAN_FRONTEND=noninteractive apt install -y wireguard
+ sudo DEBIAN_FRONTEND=noninteractive apt install -y resolvconf
+fi
+
+# Step 2: Create directories for keys and configuration
+sudo mkdir -p "$SERVER_KEYS_DIR"
+sudo mkdir -p "$WG_DIR"
+
+# Step 3: Generate Server Keys
+sudo echo $WG_SERVER_PRIVATE_KEY > "$SERVER_KEYS_DIR/${WG_INTERFACE}_privatekey"
+sudo echo $WG_SERVER_PUBLIC_KEY > "$SERVER_KEYS_DIR/${WG_INTERFACE}_publickey"
+server_private_key=$(sudo cat "$SERVER_KEYS_DIR/${WG_INTERFACE}_privatekey")
+
+# Step 4: Create Server Configuration File
+sudo bash -c "cat > $SERVER_CONF <