Dockerfile refine

Change-Id: I9ce10095247e8e339fab36cb64f0f62ffc091bd0
This commit is contained in:
George Kitsos 2024-03-21 15:02:25 +02:00 committed by Radosław Piliszek
parent b6559c905d
commit 99847caaac
61 changed files with 3068 additions and 137 deletions

View File

@ -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

View File

@ -25,6 +25,10 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "nebulous-security-manager.serviceAccountName" . }}
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;']
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:

View File

@ -5,7 +5,7 @@
replicaCount: 1
image:
repository: "quay.io/nebulous/security-manager-java-spring-boot-demo"
repository: "quay.io/nebulous/security-manager-security-layer"
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
@ -38,7 +38,7 @@ securityContext: {}
service:
type: ClusterIP
port: 80
port: 8080
ingress:
enabled: false
@ -80,3 +80,12 @@ nodeSelector: {}
tolerations: []
affinity: {}
postgresql:
global:
postgresql:
auth:
postgresPassword: "nebulous"
username: "postgresql"
password: "postgresql"
database: "postgres"

View File

@ -1,33 +0,0 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

View File

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

View File

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

View File

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

View File

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

View File

@ -1,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() {
}
}

View File

@ -0,0 +1,4 @@
!target/*-runner
!target/*-runner.jar
!target/lib/*
!target/quarkus-app/*

19
security-layer/.env Normal file
View File

@ -0,0 +1,19 @@
QUARKUS_KUBERNETES_CLIENT_MASTER_URL=
QUARKUS_KUBERNETES_CLIENT_USERNAME=
QUARKUS_KUBERNETES_CLIENT_CA_CERT_DATA=
QUARKUS_KUBERNETES_CLIENT_CLIENT_CERT_DATA=
QUARKUS_KUBERNETES_CLIENT_CLIENT_KEY_DATA=
QUARKUS_KUBERNETES_IMAGE_PULL_POLICY=ifNotPresent
QUARKUS_KUBERNETES_CLIENT_NAMESPACE=
QUARKUS_DEPLOY_TARGET=
QUARKUS_NATIVE_ADDITIONAL_BUILD_ARGS=-march=compatibility
QUARKUS_CONTAINER_IMAGE_BUILD=
QUARKUS_CONTAINER_IMAGE_GROUP=
QUARKUS_CONTAINER_IMAGE_NAME=
QUARKUS_CONTAINER_IMAGE_TAG=
RESPONSE_TOPIC=

43
security-layer/.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
#Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
release.properties
.flattened-pom.xml
# Eclipse
.project
.classpath
.settings/
bin/
# IntelliJ
.idea
*.ipr
*.iml
*.iws
# NetBeans
nb-configuration.xml
# Visual Studio Code
.vscode
.factorypath
# OSX
.DS_Store
# Vim
*.swp
*.swo
# patch
*.orig
*.rej
# Local environment
.env.ubi
# Plugin directory
/.quarkus/cli/plugins/

View File

@ -0,0 +1,9 @@
image: maven:3.8.4-openjdk-17
stages:
- docker-build
docker-build-job:
stage: docker-build
script:
- mvn package -DskipTests -Dquarkus.container-image.build=true

View File

@ -0,0 +1 @@
maven-wrapper.jar

View File

@ -0,0 +1,84 @@
/*
* 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.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public final class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "3.2.0";
private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("MVNW_VERBOSE"));
public static void main(String[] args) {
log("Apache Maven Wrapper Downloader " + WRAPPER_VERSION);
if (args.length != 2) {
System.err.println(" - ERROR wrapperUrl or wrapperJarPath parameter missing");
System.exit(1);
}
try {
log(" - Downloader started");
final URL wrapperUrl = new URL(args[0]);
final String jarPath = args[1].replace("..", ""); // Sanitize path
final Path wrapperJarPath = Paths.get(jarPath).toAbsolutePath().normalize();
downloadFileFromURL(wrapperUrl, wrapperJarPath);
log("Done");
} catch (IOException e) {
System.err.println("- Error downloading: " + e.getMessage());
if (VERBOSE) {
e.printStackTrace();
}
System.exit(1);
}
}
private static void downloadFileFromURL(URL wrapperUrl, Path wrapperJarPath)
throws IOException {
log(" - Downloading to: " + wrapperJarPath);
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
final String username = System.getenv("MVNW_USERNAME");
final char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
try (InputStream inStream = wrapperUrl.openStream()) {
Files.copy(inStream, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING);
}
log(" - Downloader complete");
}
private static void log(String msg) {
if (VERBOSE) {
System.out.println(msg);
}
}
}

View File

@ -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.9.6/apache-maven-3.9.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar

26
security-layer/Dockerfile Normal file
View File

@ -0,0 +1,26 @@
# 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 -DskipTests
# Package stage
FROM registry.access.redhat.com/ubi8/openjdk-17:1.18
# Set environment variables
ENV LANGUAGE='en_US:en'
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
# Copy built artifact from the build stage
COPY --from=build /home/app/target/quarkus-app/lib/ /deployments/lib/
COPY --from=build /home/app/target/quarkus-app/*.jar /deployments/
COPY --from=build /home/app/target/quarkus-app/app/ /deployments/app/
COPY --from=build /home/app/target/quarkus-app/quarkus/ /deployments/quarkus/
# Expose port and define user
EXPOSE 8080
USER 185
# Set the entrypoint
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

25
security-layer/README.md Normal file
View File

@ -0,0 +1,25 @@
# Security Manager
If not already installed, set up k8s-gatekeeper in your Kubernetes cluster. Follow the instructions provided in the [k8s-gatekeeper repository](https://github.com/npapageorgopoulos12/k8s-gatekeeper).
### Prerequisites
**Kubeconfig:** File used by Kubernetes clients
**Access to Kubernetes Cluster:** Ensure you have access to the Kubernetes cluster and the necessary permissions to interact with the resources your application will manage
### Configuring Environment Variables
Based on kubeconfig file, set the following environment variables:
1. KUBERNETES_CLIENT_MASTER_URL: The URL of the Kubernetes API server.
2. KUBERNETES_CLIENT_USERNAME: The username for Kubernetes cluster authentication
3. KUBERNETES_CLIENT_CA_CERT_DATA: The CA certificate data for the Kubernetes cluster.
4. KUBERNETES_CLIENT_CLIENT_CERT_DATA: The client certificate data for authentication
5. KUBERNETES_CLIENT_CLIENT_KEY_DATA: The client key data for authentication
6. KUBERNETES_CLIENT_NAMESPACE: The default namespace for your Kubernetes operations
### Accessing The Client
The application and DevUI are on _port 8080_

View File

@ -0,0 +1,34 @@
version: '3.8'
services:
# activemq-artemis:
# image: quay.io/artemiscloud/activemq-artemis-broker:1.0.21
# environment:
# AMQ_USER: quarkus
# AMQ_PASSWORD: quarkus
# AMQ_EXTRA_ARGS: "--host 0.0.0.0 --http-host 0.0.0.0 --relax-jolokia"
# ports:
# - "8161:8161" # Web Server
# - "61616:61616" # Core,MQTT,AMQP,HORNETQ,STOMP,Openwire
# - "5672:5672" # AMQP
# restart: unless-stopped
#
activemq:
image: rmohr/activemq:latest
environment:
ACTIVEMQ_ADMIN_LOGIN: quarkus
ACTIVEMQ_ADMIN_PASSWORD: quarkus
ACTIVEMQ_USER_LOGIN: quarkus
ACTIVEMQ_USER_PASSWORD: quarkus
ports:
- "8161:8161" # Web Console
- "61616:61616" # JMS
- "5672:5672" # AMQP
- "61613:61613" # STOMP
- "1883:1883" # MQTT
- "61614:61614" # WS
restart: unless-stopped

308
security-layer/mvnw vendored Executable file
View File

@ -0,0 +1,308 @@
#!/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
#
# 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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.2.0
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# 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
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=$(java-config --jre-home)
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -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 "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); 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 2>/dev/null; \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
# 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/.." || exit 1; pwd)
fi
# end of workaround
done
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
# Remove \r in case we run on Windows within Git Bash
# and check out the repository with auto CRLF management
# enabled. Otherwise, we may read lines that are delimited with
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
# splitting rules.
tr -s '\r\n' ' ' < "$1"
fi
}
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
##########################################################################################
# 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.
##########################################################################################
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
if [ -r "$wrapperJarPath" ]; then
log "Found $wrapperJarPath"
else
log "Couldn't find $wrapperJarPath, downloading it ..."
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
fi
while IFS="=" read -r key value; do
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
safeValue=$(echo "$value" | tr -d '\r')
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
log "Downloading from: $wrapperUrl"
if $cygwin; then
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
fi
if command -v wget > /dev/null; then
log "Found wget ... using wget"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
log "Found curl ... using curl"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
fi
else
log "Falling back to using Java to download"
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=$(cygpath --path --windows "$javaSource")
javaClass=$(cygpath --path --windows "$javaClass")
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
log " - Compiling MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
log " - Running MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
wrapperSha256Sum=""
while IFS="=" read -r key value; do
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
if [ -n "$wrapperSha256Sum" ]; then
wrapperSha256Result=false
if command -v sha256sum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
elif command -v shasum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
exit 1
fi
if [ $wrapperSha256Result = false ]; then
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
exit 1
fi
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 "$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
# shellcheck disable=SC2086 # safe args
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

205
security-layer/mvnw.cmd vendored Normal file
View File

@ -0,0 +1,205 @@
@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 http://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 Apache Maven Wrapper startup batch script, version 3.2.0
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@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 WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_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 WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_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('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
SET WRAPPER_SHA_256_SUM=""
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
)
IF NOT %WRAPPER_SHA_256_SUM%=="" (
powershell -Command "&{"^
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
" exit 1;"^
"}"^
"}"
if ERRORLEVEL 1 goto error
)
@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%

190
security-layer/pom.xml Normal file
View File

@ -0,0 +1,190 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>ubi.nebulous</groupId>
<artifactId>casbin-models</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.11.0</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.6.1</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.1.2</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-qpid-jms-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>com.asyncapi</groupId>
<artifactId>asyncapi-core</artifactId>
<version>1.0.0-EAP-2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.amqphub.quarkus</groupId>
<artifactId>quarkus-qpid-jms</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
</annotationProcessorPaths>
<source>${maven.compiler.release}</source>
<target>${maven.compiler.release}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,97 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/casbin-models-jvm .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/casbin-models-jvm
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/casbin-models-jvm
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi8/openjdk-17:1.18
ENV LANGUAGE='en_US:en'
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

View File

@ -0,0 +1,93 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package -Dquarkus.package.type=legacy-jar
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/casbin-models-legacy-jar .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/casbin-models-legacy-jar
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/casbin-models-legacy-jar
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi8/openjdk-17:1.18
ENV LANGUAGE='en_US:en'
COPY target/lib/* /deployments/lib/
COPY target/*-runner.jar /deployments/quarkus-run.jar
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

View File

@ -0,0 +1,27 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native -t quarkus/casbin-models .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/casbin-models
#
###
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]

View File

@ -0,0 +1,30 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
# It uses a micro base image, tuned for Quarkus native executables.
# It reduces the size of the resulting container image.
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/casbin-models .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/casbin-models
#
###
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]

View File

@ -0,0 +1,25 @@
package ubi.nebulous;
import jakarta.ws.rs.core.Application;
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
import org.eclipse.microprofile.openapi.annotations.info.Contact;
import org.eclipse.microprofile.openapi.annotations.info.Info;
import org.eclipse.microprofile.openapi.annotations.info.License;
@OpenAPIDefinition(
info = @Info(
title = "Casbin Policy Engine Client",
version = "1.0.0",
description = "API for managing Casbin resource policies in Kubernetes.",
contact = @Contact(
name = "Nikos Papageorgopoulos",
url = "https://ubitech.eu",
email = "npapageorgopoulos@ubitech.eu"
),
license = @License(
name = "Apache 2.0",
url = "http://www.apache.org/licenses/LICENSE-2.0.html"
)
)
)
public class APIConfiguration extends Application {}

View File

@ -0,0 +1,18 @@
package ubi.nebulous;
import io.vertx.core.cli.annotations.Hidden;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Hidden
@Path("/hello")
public class ExampleResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy";
}
}

View File

@ -0,0 +1,15 @@
package ubi.nebulous;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
@Liveness
public class MyLivenessCheck implements HealthCheck {
@Override
public HealthCheckResponse call() {
return HealthCheckResponse.up("alive");
}
}

View File

@ -0,0 +1,18 @@
package ubi.nebulous.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CasbinModelDTO {
private String name;
private boolean enabled;
private String modelText;
private String namespace;
}

View File

@ -0,0 +1,17 @@
package ubi.nebulous.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CasbinPolicyDTO {
private String name;
private String policyItem;
private String namespace;
}

View File

@ -0,0 +1,31 @@
package ubi.nebulous.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class DeploymentDTO implements Serializable {
private String namespace;
private String name;
private String image;
private int replicas;
private int containerPort;
@Override
public String toString() {
return "DeploymentDTO{" +
"namespace='" + namespace + '\'' +
", name='" + name + '\'' +
", image='" + image + '\'' +
", replicas=" + replicas +
", containerPort=" + containerPort +
'}';
}
}

View File

@ -0,0 +1,19 @@
package ubi.nebulous.dto.mapper;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import ubi.nebulous.dto.CasbinModelDTO;
import ubi.nebulous.model.casbin.model.CasbinModel;
@Mapper(componentModel = "cdi")
public interface CasbinModelMapper {
CasbinModelMapper INSTANCE = Mappers.getMapper(CasbinModelMapper.class);
@Mapping(target = "metadata.name", source = "name")
CasbinModel dtoToModel(CasbinModelDTO dto);
@Mapping(target = "name", source = "metadata.name")
CasbinModelDTO modelToDto(CasbinModel model);
}

View File

@ -0,0 +1,19 @@
package ubi.nebulous.dto.mapper;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import ubi.nebulous.dto.CasbinPolicyDTO;
import ubi.nebulous.model.casbin.policy.CasbinPolicy;
@Mapper(componentModel = "cdi")
public interface CasbinPolicyMapper {
CasbinPolicyMapper INSTANCE = Mappers.getMapper(CasbinPolicyMapper.class);
@Mapping(target = "metadata.name", source = "name")
CasbinPolicy dtoToModel(CasbinPolicyDTO dto);
@Mapping(target = "name", source = "metadata.name")
CasbinPolicyDTO modelToDto(CasbinPolicy model);
}

View File

@ -0,0 +1,15 @@
package ubi.nebulous.dto.mapper;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import ubi.nebulous.dto.DeploymentDTO;
import ubi.nebulous.model.DeploymentModel;
@Mapper
public interface DeploymentMapper {
DeploymentMapper INSTANCE = Mappers.getMapper(DeploymentMapper.class);
DeploymentDTO modelToDTO(DeploymentModel deploymentModel);
DeploymentModel dtoToModel(DeploymentDTO deploymentDTO);
}

View File

@ -0,0 +1,148 @@
package ubi.nebulous.messaging.consumer;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.jms.*;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import ubi.nebulous.dto.CasbinModelDTO;
import ubi.nebulous.dto.CasbinPolicyDTO;
import ubi.nebulous.messaging.util.JsonUtil;
import ubi.nebulous.model.casbin.model.CasbinModel;
import ubi.nebulous.service.CasbinModelService;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ApplicationScoped
public class CasbinModelConsumer implements Runnable {
private static final Logger logger = Logger.getLogger(CasbinModelConsumer.class);
@Inject
ConnectionFactory connectionFactory;
@Inject
CasbinModelService casbinModelService;
@ConfigProperty(name = "CASBIN_MODEL_CREATE_TOPIC")
String casbinModelCreateTopic;
@ConfigProperty(name = "CASBIN_MODEL_DELETE_TOPIC")
String casbinModelDeleteTopic;
@ConfigProperty(name = "CASBIN_MODEL_GET_ALL_TOPIC")
String casbinModelGetAllTopic;
@ConfigProperty(name = "RESPONSE_TOPIC")
String responseTopicName;
private final ExecutorService scheduler = Executors.newSingleThreadExecutor();
void onStart(@Observes StartupEvent ev) {
logger.info("Starting CasbinModel Consumer...");
scheduler.submit(this);
}
void onStop(@Observes ShutdownEvent ev) {
logger.info("Stopping CasbinModel Consumer...");
scheduler.shutdown();
}
@Override
public void run() {
try (JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE)) {
var createConsumer = context.createConsumer(context.createTopic(casbinModelCreateTopic));
var deleteConsumer = context.createConsumer(context.createTopic(casbinModelDeleteTopic));
var getAllConsumer = context.createConsumer(context.createTopic(casbinModelGetAllTopic));
while (!Thread.currentThread().isInterrupted()) {
processMessages(createConsumer, deleteConsumer, getAllConsumer, context);
}
} catch (RuntimeException e) {
logger.errorf(e, "Error in CasbinModel Consumer.");
}
}
private void processMessages(JMSConsumer createConsumer, JMSConsumer deleteConsumer, JMSConsumer getAllConsumer, JMSContext context) {
try {
var createMessage = createConsumer.receiveNoWait();
if (createMessage != null) {
processCreateOrUpdateCasbinModel(createMessage.getBody(List.class), context);
}
var deleteMessage = deleteConsumer.receiveNoWait();
if (deleteMessage != null) {
processDeleteCasbinModel(deleteMessage.getBody(String.class), context);
}
var getAllMessage = getAllConsumer.receiveNoWait();
if (getAllMessage != null) {
processListCasbinModels(getAllMessage.getBody(String.class), context);
}
} catch (JMSException e) {
logger.errorf(e, "Error processing messages in CasbinModel Consumer.");
}
}
private void processCreateOrUpdateCasbinModel(List<Map<String, String>> messageList, JMSContext context) {
try {
Map<String, String> modelMap = messageList.get(0);
CasbinModelDTO casbinModelDTO = new CasbinModelDTO();
casbinModelDTO.setName(modelMap.get("name") != null ? modelMap.get("name") : null);
casbinModelDTO.setModelText(modelMap.get("model") != null ? modelMap.get("model") : null);
casbinModelDTO.setNamespace(modelMap.get("namespace") != null ? modelMap.get("namespace") : null);
// CasbinModelDTO casbinModelDTO = JsonUtil.deserialize(jsonMessage, CasbinModelDTO.class);
logger.infof("message received for "+ casbinModelDTO.toString());
CasbinModel model = casbinModelService.createOrUpdateCasbinModel(casbinModelDTO);
sendResponse(context, "CasbinModel created/updated successfully");
} catch (Exception e) {
sendResponse(context, "Error creating/updating CasbinModel: " + e.getMessage());
}
}
private void processDeleteCasbinModel(String jsonMessage, JMSContext context) {
try {
JsonObject jsonObject = JsonParser.parseString(jsonMessage).getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String namespace = jsonObject.has("namespace") ? jsonObject.get("namespace").getAsString() : "default";
if (casbinModelService.casbinModelExists(name, namespace)) {
casbinModelService.deleteCasbinModel(name, namespace);
sendResponse(context, String.format("CasbinModel '%s' in namespace '%s' deleted successfully", name, namespace));
} else {
sendResponse(context, String.format("CasbinModel '%s' in namespace '%s' not found", name, namespace));
}
} catch (Exception e) {
logger.errorf(e, "Error processing delete CasbinModel message.");
sendResponse(context, "Error deleting CasbinModel: " + e.getMessage());
}
}
private void processListCasbinModels(String namespace, JMSContext context) {
try {
List<CasbinModel> models = casbinModelService.listCasbinModels(namespace != null ? namespace : "default");
sendResponse(context, JsonUtil.serialize(models));
logger.infof(JsonUtil.serialize(models));
} catch (Exception e) {
logger.errorf(e, "Error processing list CasbinModels message.");
sendResponse(context, "Error retrieving CasbinModels: " + e.getMessage());
}
}
private void sendResponse(JMSContext context, String message) {
try {
TextMessage responseMessage = context.createTextMessage(message);
context.createProducer().send(context.createTopic(responseTopicName), responseMessage);
} catch (RuntimeException e) {
logger.errorf(e, "Error sending response message.");
}
}
}

View File

@ -0,0 +1,149 @@
package ubi.nebulous.messaging.consumer;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.jms.*;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import ubi.nebulous.dto.CasbinModelDTO;
import ubi.nebulous.dto.CasbinPolicyDTO;
import ubi.nebulous.messaging.util.JsonUtil;
import ubi.nebulous.model.casbin.policy.CasbinPolicy;
import ubi.nebulous.service.CasbinPolicyService;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ApplicationScoped
public class CasbinPolicyConsumer implements Runnable {
private static final Logger logger = Logger.getLogger(CasbinPolicyConsumer.class);
@Inject
ConnectionFactory connectionFactory;
@Inject
CasbinPolicyService casbinPolicyService;
@ConfigProperty(name = "CASBIN_POLICY_CREATE_TOPIC")
String casbinPolicyCreateTopic;
@ConfigProperty(name = "CASBIN_POLICY_DELETE_TOPIC")
String casbinPolicyDeleteTopic;
@ConfigProperty(name = "CASBIN_POLICY_GET_ALL_TOPIC")
String casbinPolicyGetAllTopic;
@ConfigProperty(name = "RESPONSE_TOPIC")
String responseTopicName;
private final ExecutorService scheduler = Executors.newSingleThreadExecutor();
void onStart(@Observes StartupEvent ev) {
logger.info("Starting CasbinPolicy Consumer...");
scheduler.submit(this);
}
void onStop(@Observes ShutdownEvent ev) {
logger.info("Stopping CasbinPolicy Consumer...");
scheduler.shutdown();
}
@Override
public void run() {
try (JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE)) {
var createConsumer = context.createConsumer(context.createTopic(casbinPolicyCreateTopic));
var deleteConsumer = context.createConsumer(context.createTopic(casbinPolicyDeleteTopic));
var getAllConsumer = context.createConsumer(context.createTopic(casbinPolicyGetAllTopic));
while (!Thread.currentThread().isInterrupted()) {
processMessages(createConsumer, deleteConsumer, getAllConsumer, context);
}
} catch (RuntimeException e) {
logger.errorf(e, "Error in CasbinPolicy Consumer.");
}
}
private void processMessages(JMSConsumer createConsumer, JMSConsumer deleteConsumer, JMSConsumer getAllConsumer, JMSContext context) {
try {
var createMessage = createConsumer.receiveNoWait();
if (createMessage != null) {
// processCreateOrUpdateCasbinPolicy(createMessage.getBody(String.class), context);
processCreateOrUpdateCasbinPolicy(createMessage.getBody(List.class), context);
}
var deleteMessage = deleteConsumer.receiveNoWait();
if (deleteMessage != null) {
processDeleteCasbinPolicy(deleteMessage.getBody(String.class), context);
}
var getAllMessage = getAllConsumer.receiveNoWait();
if (getAllMessage != null) {
processListCasbinPolicies(getAllMessage.getBody(String.class), context);
}
} catch (JMSException e) {
logger.errorf(e, "Error processing messages in CasbinPolicy Consumer.");
}
}
private void processCreateOrUpdateCasbinPolicy(List<Map<String, String>> messageList, JMSContext context) {
try {
Map<String, String> policyMap = messageList.get(0);
CasbinPolicyDTO casbinPolicyDTO = new CasbinPolicyDTO();
casbinPolicyDTO.setName(policyMap.get("name") != null ? policyMap.get("name") : null);
casbinPolicyDTO.setPolicyItem(policyMap.get("policyItem") != null ? policyMap.get("policyItem") : null);
casbinPolicyDTO.setNamespace(policyMap.get("namespace") != null ? policyMap.get("namespace") : null);
// CasbinPolicyDTO dto = JsonUtil.deserialize(jsonMessage, CasbinPolicyDTO.class);
logger.infof("message received for "+ casbinPolicyDTO.toString());
CasbinPolicy policy = casbinPolicyService.createOrUpdateCasbinPolicy(casbinPolicyDTO);
sendResponse(context, "CasbinPolicy created/updated successfully");
} catch (Exception e) {
sendResponse(context, "Error creating/updating CasbinPolicy: " + e.getMessage());
}
}
private void processDeleteCasbinPolicy(String jsonMessage, JMSContext context) {
try {
JsonObject jsonObject = JsonParser.parseString(jsonMessage).getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String namespace = jsonObject.has("namespace") ? jsonObject.get("namespace").getAsString() : "default";
if (casbinPolicyService.casbinPolicyExists(name, namespace)) {
casbinPolicyService.deleteCasbinPolicy(name, namespace);
sendResponse(context, String.format("CasbinPolicy '%s' deleted successfully", name));
} else {
sendResponse(context, String.format("CasbinPolicy '%s' not found", name));
logger.infof("CasbinPolicy '%s' not found", name);
}
} catch (Exception e) {
sendResponse(context, "Error deleting CasbinPolicy: " + e.getMessage());
}
}
private void processListCasbinPolicies(String namespace, JMSContext context) {
try {
List<CasbinPolicy> policies = casbinPolicyService.listCasbinPolicies(namespace);
sendResponse(context, JsonUtil.serialize(policies));
logger.infof("Listed CasbinPolicies for namespace: %s", namespace);
} catch (Exception e) {
sendResponse(context, "Error listing CasbinPolicies: " + e.getMessage());
}
}
private void sendResponse(JMSContext context, String message) {
try {
TextMessage responseMessage = context.createTextMessage(message);
context.createProducer().send(context.createTopic(responseTopicName), responseMessage);
} catch (RuntimeException e) {
logger.errorf(e, "Error sending response message.");
}
}
}

View File

@ -0,0 +1,145 @@
package ubi.nebulous.messaging.consumer;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.jms.*;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import ubi.nebulous.messaging.util.JsonUtil;
import ubi.nebulous.dto.DeploymentDTO;
import ubi.nebulous.service.DeploymentService;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ApplicationScoped
public class DeploymentConsumer implements Runnable {
private static final Logger logger = Logger.getLogger(DeploymentConsumer.class);
@Inject
ConnectionFactory connectionFactory;
@Inject
DeploymentService k8sDeploymentService;
@ConfigProperty(name = "DEPLOYMENT_CREATE_TOPIC")
String deploymentCreateTopic;
@ConfigProperty(name = "DEPLOYMENT_DELETE_TOPIC")
String deploymentDeleteTopic;
@ConfigProperty(name = "DEPLOYMENT_GET_ALL_TOPIC")
String deploymentGetAllTopic;
@ConfigProperty(name = "RESPONSE_TOPIC")
String responseTopicName;
private final ExecutorService scheduler = Executors.newSingleThreadExecutor();
void onStart(@Observes StartupEvent ev) {
logger.info("Starting Deployment Consumer...");
scheduler.submit(this);
}
void onStop(@Observes ShutdownEvent ev) {
logger.info("Stopping Deployment Consumer...");
scheduler.shutdown();
}
@Override
public void run() {
try (JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE)) {
var createConsumer = context.createConsumer(context.createTopic(deploymentCreateTopic));
var deleteConsumer = context.createConsumer(context.createTopic(deploymentDeleteTopic));
var getAllConsumer = context.createConsumer(context.createTopic(deploymentGetAllTopic));
while (!Thread.currentThread().isInterrupted()) {
processMessages(createConsumer, deleteConsumer, getAllConsumer, context);
}
}
}
private void processMessages(JMSConsumer createConsumer, JMSConsumer deleteConsumer, JMSConsumer getAllConsumer, JMSContext context) {
var createMessage = createConsumer.receiveNoWait();
if (createMessage != null) {
try {
processCreateDeployment(createMessage.getBody(String.class), context);
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
var deleteMessage = deleteConsumer.receiveNoWait();
if (deleteMessage != null) {
try {
processDeleteDeployment(deleteMessage.getBody(String.class), context);
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
var getAllMessage = getAllConsumer.receiveNoWait();
if (getAllMessage != null) {
try {
processGetAllDeployments(getAllMessage.getBody(String.class), context);
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
}
private void processCreateDeployment(String jsonMessage, JMSContext context) {
try {
DeploymentDTO deploymentDTO = JsonUtil.deserialize(jsonMessage, DeploymentDTO.class);
logger.infof("Received Create Deployment Message: %s", deploymentDTO);
k8sDeploymentService.createDeployment(deploymentDTO);
sendResponse(context, "Deployment created successfully");
} catch (Exception e) {
sendResponse(context, "Error creating deployment: " + e.getMessage());
}
}
private void processDeleteDeployment(String jsonMessage, JMSContext context) {
try {
JsonObject jsonObject = JsonParser.parseString(jsonMessage).getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String namespace = jsonObject.has("namespace") ? jsonObject.get("namespace").getAsString() : "default";
if (k8sDeploymentService.deploymentExists(name, namespace)) {
k8sDeploymentService.deleteDeployment(name, namespace);
sendResponse(context, String.format("Deployment '%s' in namespace '%s' deleted successfully", name, namespace));
} else {
logger.infof("Deployment '%s' in namespace '%s' not found", name, namespace);
sendResponse(context, String.format("Deployment '%s' in namespace '%s' not found", name, namespace));
}
} catch (Exception e) {
sendResponse(context, "Error deleting deployment: " + e.getMessage());
}
}
private void processGetAllDeployments(String namespace, JMSContext context) {
try {
List<Deployment> deployments = k8sDeploymentService.getDeployments(namespace != null ? namespace : "default");
logger.infof("Received Get All Deployments Message for Namespace: %s", namespace);
// send back list of deployments
logger.infof(JsonUtil.serialize(deployments));
sendResponse(context, JsonUtil.serialize(deployments));
} catch (Exception e) {
sendResponse(context, "Error retrieving deployments: " + e.getMessage());
}
}
private void sendResponse(JMSContext context, String message) {
TextMessage responseMessage = context.createTextMessage(message);
context.createProducer().send(context.createTopic(responseTopicName), responseMessage);
}
}

View File

@ -0,0 +1,27 @@
package ubi.nebulous.messaging.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class JsonUtil {
private static final ObjectMapper objectMapper = new ObjectMapper();
public static <T> T deserialize(String json, Class<T> clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (IOException e) {
throw new RuntimeException("Error deserializing JSON", e);
}
}
public static String serialize(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException("Error serializing object to JSON", e);
}
}
}

View File

@ -0,0 +1,24 @@
package ubi.nebulous.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class DeploymentModel {
private String namespace;
private String name;
private String image;
private int replicas;
private int containerPort;
// if there is no namespace use default
public String getNamespace() {
return namespace != null ? namespace : "default";
}
}

View File

@ -0,0 +1,26 @@
package ubi.nebulous.model.casbin.model;
import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.Version;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Group("auth.casbin.org")
@Version("v1")
public class CasbinModel extends CustomResource<CasbinModelSpec,CasbinModelStatus> implements Namespaced {
private String namespace;
@Override
public String toString() {
return "CasbinModel{" +
"spec=" + spec +
", status=" + status +
'}';
}
}

View File

@ -0,0 +1,12 @@
package ubi.nebulous.model.casbin.model;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CasbinModelSpec implements KubernetesResource {
private boolean enabled;
private String modelText;
}

View File

@ -0,0 +1,6 @@
package ubi.nebulous.model.casbin.model;
import io.fabric8.kubernetes.api.model.KubernetesResource;
public class CasbinModelStatus implements KubernetesResource {
}

View File

@ -0,0 +1,28 @@
package ubi.nebulous.model.casbin.policy;
import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.Version;
import lombok.Getter;
import lombok.Setter;
import javax.naming.Name;
@Getter
@Setter
@Group("auth.casbin.org")
@Version("v1")
public class CasbinPolicy extends CustomResource<CasbinPolicySpec,CasbinPolicyStatus> implements Namespaced {
private String namespace;
@Override
public String toString() {
return "CasbinPolicy{" +
"metadata=" + getMetadata() +
", spec=" + spec +
", status=" + status +
'}';
}
}

View File

@ -0,0 +1,11 @@
package ubi.nebulous.model.casbin.policy;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CasbinPolicySpec implements KubernetesResource {
private String policyItem;
}

View File

@ -0,0 +1,9 @@
package ubi.nebulous.model.casbin.policy;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CasbinPolicyStatus implements KubernetesResource {}

View File

@ -0,0 +1,106 @@
package ubi.nebulous.rest;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
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.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import ubi.nebulous.dto.CasbinModelDTO;
import ubi.nebulous.dto.mapper.CasbinModelMapper;
import ubi.nebulous.model.DeploymentModel;
import ubi.nebulous.model.casbin.model.CasbinModel;
import ubi.nebulous.service.CasbinModelService;
import java.util.List;
@Path("/casbin-model")
public class CasbinModelResource {
@Inject
CasbinModelService casbinModelService;
/**
* Creates a CasbinModel based on the provided DTO
*
* @param casbinModelDTO The CasbinModel containing the relevant policy model
* @return The created CasbinModel resource as object
*/
@POST
@Operation(summary = "Create a CasbinModel", description = "Creates a CasbinModel based on the provided Policy Model.")
@RequestBody(required = true, content = @Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(implementation = CasbinModelDTO.class),
examples = @ExampleObject(name = "example",
value = "{\n" +
" \"name\": \"allowed-repo\",\n" +
" \"enabled\": true,\n" +
" \"modelText\": \"[request_definition]\\nr = obj\\n\\n[policy_definition]\\np = obj,eft\\n\\n[policy_effect]\\ne = !some(where (p.eft == deny))\\n\\n[matchers]\\nm = ${NAMESPACE} == \\\"default\\\" && ${RESOURCE} ==\\\"deployments\\\" && access(${OBJECT}.Spec.Template.Spec.Containers , 0, \\\"Image\\\") == p.obj\"\n" +
"}")
))
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createOrUpdateCasbinModel(CasbinModelDTO casbinModelDTO) {
try {
CasbinModel createdModel = casbinModelService.createOrUpdateCasbinModel(casbinModelDTO);
return Response.status(Response.Status.CREATED).entity(createdModel).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error creating/updating CasbinModel: " + e.getMessage())
.build();
}
}
/**
* lists crd of CasbinModel in the specified namespace.
*
* @param namespace from which to retrieve CasbinModel
* @return A list of CasbinModel
*/
@GET
@Path("/{namespace}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Retrieves CasbinModel CRDs", description = "Retrieves a list of CasbinModel CRDs.")
public Response listCasbinModels(@PathParam("namespace") @DefaultValue("default") String namespace) {
try {
List<CasbinModel> models = casbinModelService.listCasbinModels(namespace);
return Response.ok(models).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error listing CasbinModels: " + e.getMessage())
.build();
}
}
/**
* Deletes CasbinModel with the given name
*
* @param casbinModelName The name of the CasbinModel to be deleted
* @return response indicating the outcome of the delete operation
*/
@DELETE
@Path("/{casbinModelName}")
@Parameter(name = "casbinmodelname", description = "The name of the CasbinModel to be deleted", required = true)
@Operation(summary = "Deletes a Kubernetes CasbinModel CRD", description = "Deletes a CasbinModel CRD based on the provided casbinmodelname.")
@Produces(MediaType.TEXT_PLAIN)
public Response deleteCasbinModel(@PathParam("casbinModelName") String casbinModelName, @QueryParam("namespace") @DefaultValue("default") String namespace) {
try {
if (!casbinModelService.casbinModelExists(casbinModelName, namespace)) {
return Response.status(Response.Status.NOT_FOUND)
.entity("CasbinModel not found")
.build();
}
casbinModelService.deleteCasbinModel(casbinModelName, namespace);
return Response.ok("CasbinModel deleted").build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error deleting CasbinModel: " + e.getMessage())
.build();
}
}
}

View File

@ -0,0 +1,105 @@
package ubi.nebulous.rest;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
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.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import ubi.nebulous.dto.CasbinModelDTO;
import ubi.nebulous.dto.CasbinPolicyDTO;
import ubi.nebulous.dto.mapper.CasbinPolicyMapper;
import ubi.nebulous.model.casbin.policy.CasbinPolicy;
import ubi.nebulous.service.CasbinPolicyService;
import java.util.List;
@Path("/casbin-policy")
public class CasbinPolicyResource {
@Inject
CasbinPolicyService casbinPolicyService;
/**
* Creates a CasbinPolicy based on the provided DTO
*
* @param casbinPolicyDTO containing the relevant policy
* @return The created CasbinPolicy resource as object
*/
@POST
@Operation(summary = "Create or Update a CasbinPolicy", description = "Creates or updates a CasbinPolicy based on the provided Policy DTO.")
@RequestBody(required = true, content = @Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(implementation = CasbinPolicy.class),
examples = @ExampleObject(name = "example",
value = "{\n" +
" \"name\": \"allowed-repo\",\n" +
" \"policyItem\": \"p, \\\"nginx:1.13.1\\\",allow\\np, \\\"nginx:1.14.1\\\",deny\"\n" +
" }")
))
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createOrUpdateCasbinPolicy(CasbinPolicyDTO casbinPolicyDTO) {
try {
CasbinPolicy createdPolicy = casbinPolicyService.createOrUpdateCasbinPolicy(casbinPolicyDTO);
return Response.status(Response.Status.CREATED).entity(createdPolicy).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error creating/updating CasbinPolicy: " + e.getMessage())
.build();
}
}
/**
* lists crd of CasbinPolicy in the specified namespace.
*
* @param namespace from which to retrieve CasbinPolicy
* @return A list of CasbinPolicy
*/
@GET
@Path("/{namespace}")
@Operation(summary = "List CasbinPolicies", description = "Lists all CasbinPolicies in the specified namespace.")
@Produces(MediaType.APPLICATION_JSON)
public Response listCasbinPolicies(@PathParam("namespace") String namespace) {
try {
List<CasbinPolicy> policies = casbinPolicyService.listCasbinPolicies(namespace);
return Response.ok(policies).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error listing CasbinPolicies: " + e.getMessage())
.build();
}
}
/**
* Deletes CasbinPolicy with the given name
*
* @param casbinPolicyName The name of the CasbinPolicy to be deleted
* @return response indicating the outcome of the delete operation
*/
@DELETE
@Path("/{casbinPolicyName}")
@Operation(summary = "Delete a CasbinPolicy", description = "Deletes a CasbinPolicy with the specified name from the given namespace.")
@Produces(MediaType.TEXT_PLAIN)
public Response deleteCasbinPolicy(@PathParam("casbinPolicyName") String casbinPolicyName, @QueryParam("namespace") @DefaultValue("default") String namespace) {
try {
if (!casbinPolicyService.casbinPolicyExists(casbinPolicyName, namespace)) {
return Response.status(Response.Status.NOT_FOUND)
.entity("CasbinPolicy not found")
.build();
}
casbinPolicyService.deleteCasbinPolicy(casbinPolicyName, namespace);
return Response.ok("CasbinPolicy deleted").build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error deleting CasbinPolicy: " + e.getMessage())
.build();
}
}
}

View File

@ -0,0 +1,116 @@
package ubi.nebulous.rest;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.client.KubernetesClientException;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
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.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.jboss.logging.Logger;
import ubi.nebulous.dto.DeploymentDTO;
import ubi.nebulous.model.DeploymentModel;
import ubi.nebulous.service.DeploymentService;
import java.util.List;
@Path("/deployment")
public class DeploymentResource {
private static final Logger LOG = Logger.getLogger(DeploymentResource.class);
@Inject
DeploymentService kubernetesDeploymentService;
/**
* lists deployments in the specified namespace.
*
* @param namespace from which to retrieve deployments
* @return A list of Deployments
*/
@GET
@Path("/{namespace}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Retrieves K8s Deployments", description = "Retrieves a list of Kubernetes deployments.")
public Response getDeployments(@PathParam("namespace") @DefaultValue("default") String namespace) {
try {
List<Deployment> deployments = kubernetesDeploymentService.getDeployments(namespace);
return Response.ok(deployments).build();
} catch (Exception e) {
LOG.error(e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error retrieving deployments: " + e.getMessage())
.build();
}
}
/**
* Creates a Kubernetes Deployment based on the provided DeploymentDTO
*
* @param deploymentDTO containing the deployment specifications
* @return The created Deployment resource as object
*/
@POST
@Operation(summary = "Create a Kubernetes Deployment", description = "Creates a Kubernetes Deployment based on the provided DeploymentDTO.")
@RequestBody(required = true, content = @Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(implementation = DeploymentModel.class),
examples = @ExampleObject(name = "example",
value = "{\"name\": \"nginx-deployment\", \"image\": \"nginx:1.13.1\", \"replicas\": 1, \"containerPort\": 80}")
))
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createDeployment(DeploymentDTO deploymentDTO) {
try {
Deployment deployment = kubernetesDeploymentService.createDeployment(deploymentDTO);
return Response.status(Response.Status.CREATED)
.entity(deployment)
.build();
} catch (Exception e) {
LOG.error(e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error creating deployment: " + e.getMessage())
.build();
}
}
/**
* Deletes a Kubernetes Deployment with the given name
*
* @param deploymentName The name of the deployment to be deleted
* @return response indicating the outcome of the delete operation
*/
@DELETE
@Parameter(name = "deploymentname", description = "The name of the deployment to be deleted", required = true)
@Operation(summary = "Deletes a Kubernetes Deployment", description = "Deletes a Kubernetes Deployment based on the provided deploymentname.")
@Path("/{deploymentname}")
@Produces(MediaType.TEXT_PLAIN)
public Response deleteDeployment(@PathParam("deploymentname") String deploymentName,
@QueryParam("namespace") @DefaultValue("default") String namespace) {
try {
// check if exists
boolean exists = kubernetesDeploymentService.deploymentExists(deploymentName, namespace);
if (!exists) {
return Response.status(Response.Status.NOT_FOUND)
.entity(String.format("Deployment '%s' not found in namespace '%s'.", deploymentName, namespace))
.build();
}
// delete
kubernetesDeploymentService.deleteDeployment(deploymentName, namespace);
return Response.ok()
.entity(String.format("Deployment '%s' deleted successfully from namespace '%s'.", deploymentName, namespace))
.build();
} catch (KubernetesClientException e) {
LOG.error(e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(String.format("Error deleting deployment '%s' from namespace '%s': %s", deploymentName, namespace, e.getMessage()))
.build();
}
}
}

View File

@ -0,0 +1,95 @@
package ubi.nebulous.service;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;
import ubi.nebulous.dto.CasbinModelDTO;
import ubi.nebulous.model.casbin.model.CasbinModel;
import ubi.nebulous.model.casbin.model.CasbinModelSpec;
import ubi.nebulous.model.casbin.model.CasbinModelStatus;
import java.util.List;
@ApplicationScoped
public class CasbinModelService {
private static final Logger logger = Logger.getLogger(CasbinModelService.class);
@Inject
KubernetesClient kubernetesClient;
public CasbinModel createOrUpdateCasbinModel(CasbinModelDTO dto) {
try {
String effectiveNamespace = (dto.getNamespace() != null && !dto.getNamespace().isEmpty()) ? dto.getNamespace() : "default";
CasbinModel casbinModel = new CasbinModel();
casbinModel.setMetadata(new ObjectMetaBuilder()
.withName(dto.getName())
.build());
CasbinModelSpec spec = new CasbinModelSpec();
spec.setEnabled(dto.isEnabled());
spec.setModelText(dto.getModelText());
casbinModel.setSpec(spec);
casbinModel.setStatus(new CasbinModelStatus());
kubernetesClient.resources(CasbinModel.class)
.inNamespace(effectiveNamespace)
.createOrReplace(casbinModel);
logger.infof("CasbinModel created/updated successfully: %s", casbinModel);
return casbinModel;
}catch (KubernetesClientException e){
logger.errorf(e, "Error processing create/update CasbinModel message.");
return null;
}
}
public List<CasbinModel> listCasbinModels(String namespace) {
try {
List<CasbinModel> casbinModelLists = kubernetesClient.resources(CasbinModel.class)
.inNamespace(namespace)
.list()
.getItems();
logger.infof("Received List CasbinModels Message for Namespace: %s", namespace);
return casbinModelLists;
} catch (KubernetesClientException e) {
throw new KubernetesClientException("Error listing CasbinModels: " + e.getMessage(), e);
}
}
public void deleteCasbinModel(String name, String namespace) {
String effectiveNamespace = (namespace != null && !namespace.isEmpty()) ? namespace : "default";
try {
kubernetesClient.resources(CasbinModel.class)
.inNamespace(effectiveNamespace)
.withName(name)
.delete();
logger.infof("CasbinModel '%s' in namespace '%s' deleted successfully", name, namespace);
} catch (KubernetesClientException e) {
logger.errorf(e, "Error processing deleting CasbinModel.");
throw new RuntimeException("Error deleting CasbinModel: " + e.getMessage(), e);
}
}
public boolean casbinModelExists(String name, String namespace) {
String effectiveNamespace = (namespace != null && !namespace.isEmpty()) ? namespace : "default";
try {
return kubernetesClient.resources(CasbinModel.class)
.inNamespace(effectiveNamespace)
.withName(name)
.get() != null;
} catch (KubernetesClientException e) {
throw new KubernetesClientException("Error checking CasbinModel existence: " + e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,85 @@
package ubi.nebulous.service;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;
import ubi.nebulous.dto.CasbinPolicyDTO;
import ubi.nebulous.model.casbin.policy.CasbinPolicy;
import ubi.nebulous.model.casbin.policy.CasbinPolicySpec;
import java.util.List;
@ApplicationScoped
public class CasbinPolicyService {
private static final Logger logger = Logger.getLogger(CasbinPolicyService.class);
@Inject
KubernetesClient kubernetesClient;
public CasbinPolicy createOrUpdateCasbinPolicy(CasbinPolicyDTO dto) {
String effectiveNamespace = (dto.getNamespace() != null && !dto.getNamespace().isEmpty()) ? dto.getNamespace() : "default";
try {
CasbinPolicy casbinPolicy = new CasbinPolicy();
casbinPolicy.setMetadata(new ObjectMetaBuilder().withName(dto.getName()).build());
CasbinPolicySpec spec = new CasbinPolicySpec();
spec.setPolicyItem(dto.getPolicyItem());
casbinPolicy.setSpec(spec);
kubernetesClient.resources(CasbinPolicy.class)
.inNamespace(effectiveNamespace)
.createOrReplace(casbinPolicy);
logger.infof("CasbinPolicy created/updated successfully: %s", casbinPolicy);
return casbinPolicy;
} catch (KubernetesClientException e) {
logger.errorf(e, "Error creating/updating CasbinPolicy.");
throw new RuntimeException("Error creating/updating CasbinPolicy: " + e.getMessage(), e);
}
}
public List<CasbinPolicy> listCasbinPolicies(String namespace) {
try {
List<CasbinPolicy> casbinPolicyList = kubernetesClient.resources(CasbinPolicy.class)
.inNamespace(namespace)
.list()
.getItems();
logger.infof("Listed CasbinPolicies for namespace: %s", namespace);
return casbinPolicyList;
} catch (KubernetesClientException e) {
logger.errorf(e, "Error listing CasbinPolicies.");
throw new RuntimeException("Error listing CasbinPolicies: " + e.getMessage(), e);
}
}
public void deleteCasbinPolicy(String name, String namespace) {
String effectiveNamespace = (namespace != null && !namespace.isEmpty()) ? namespace : "default";
try {
kubernetesClient.resources(CasbinPolicy.class)
.inNamespace(effectiveNamespace)
.withName(name)
.delete();
logger.infof("CasbinPolicy '%s' deleted successfully", name);
} catch (KubernetesClientException e) {
logger.errorf(e, "Error deleting CasbinPolicy.");
throw new RuntimeException("Error deleting CasbinPolicy: " + e.getMessage(), e);
}
}
public boolean casbinPolicyExists(String name, String namespace) {
String effectiveNamespace = (namespace != null && !namespace.isEmpty()) ? namespace : "default";
try {
return kubernetesClient.resources(CasbinPolicy.class)
.inNamespace(effectiveNamespace)
.withName(name)
.get() != null;
} catch (KubernetesClientException e) {
throw new RuntimeException("Error checking CasbinPolicy existence: " + e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,92 @@
package ubi.nebulous.service;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;
import ubi.nebulous.dto.DeploymentDTO;
import ubi.nebulous.dto.mapper.DeploymentMapper;
import ubi.nebulous.messaging.consumer.DeploymentConsumer;
import ubi.nebulous.model.DeploymentModel;
import java.util.List;
@ApplicationScoped
public class DeploymentService {
private static final Logger logger = Logger.getLogger(DeploymentService.class);
@Inject
KubernetesClient kubernetesClient;
public Deployment createDeployment(DeploymentDTO deploymentDTO){
DeploymentModel deploymentModel = DeploymentMapper.INSTANCE.dtoToModel(deploymentDTO);
Deployment deployment = new DeploymentBuilder()
.withNewMetadata()
.withName(deploymentDTO.getName())
.endMetadata()
.withNewSpec()
.withReplicas(deploymentDTO.getReplicas())
.withNewSelector()
.addToMatchLabels("app", deploymentDTO.getName())
.endSelector()
.withNewTemplate()
.withNewMetadata()
.addToLabels("app", deploymentDTO.getName())
.endMetadata()
.withNewSpec()
.addNewContainer()
.withName(deploymentDTO.getName())
.withImage(deploymentDTO.getImage())
.addNewPort()
.withContainerPort(deploymentDTO.getContainerPort())
.endPort()
.endContainer()
.endSpec()
.endTemplate()
.endSpec()
.build();
try {
deployment = kubernetesClient.apps().deployments()
.inNamespace(deploymentModel.getNamespace())
.createOrReplace(deployment);
logger.infof("Deployment created successfully");
} catch (KubernetesClientException e) {
logger.errorf(e, "Error processing Create Deployment message.");
e.printStackTrace();
}
return deployment;
}
public void deleteDeployment(String deploymentName, String namespace) {
try {
String effectiveNamespace = (namespace != null && !namespace.isEmpty()) ? namespace : "default";
kubernetesClient.apps().deployments().inNamespace(effectiveNamespace)
.withName(deploymentName).delete();
logger.infof("Deployment '%s' in namespace '%s' deleted successfully", deploymentName, namespace);
}catch (RuntimeException e){
logger.errorf(e, "Error processing Delete Deployment message.");
}
}
public boolean deploymentExists(String deploymentName, String namespace) {
String effectiveNamespace = (namespace != null && !namespace.isEmpty()) ? namespace : "default";
return kubernetesClient.apps().deployments().inNamespace(effectiveNamespace)
.withName(deploymentName).get() != null;
}
public List<Deployment> getDeployments(String namespace) {
try {
return kubernetesClient.apps().deployments().inNamespace(namespace).list().getItems();
}catch (RuntimeException e){
logger.errorf(e, "Error processing Get All Deployments message.");
return null;
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,33 @@
quarkus.banner.path=banner.txt
# Kubernetes Client Configuration
# The actual values are expected to be provided via environment variables
quarkus.kubernetes-client.master-url=${KUBERNETES_CLIENT_MASTER_URL:https://default-url:6443}
quarkus.kubernetes-client.username=${KUBERNETES_CLIENT_USERNAME:default-user}
quarkus.kubernetes-client.ca-cert-data=${KUBERNETES_CLIENT_CA_CERT_DATA:default-ca-cert}
quarkus.kubernetes-client.client-cert-data=${KUBERNETES_CLIENT_CLIENT_CERT_DATA:default-cert}
quarkus.kubernetes-client.client-key-data=${KUBERNETES_CLIENT_CLIENT_KEY_DATA:default-key}
quarkus.kubernetes.image-pull-policy=ifNotPresent
quarkus.kubernetes-client.namespace=${KUBERNETES_CLIENT_NAMESPACE:default}
quarkus.deploy.target=kubernetes
# Additional build arguments
quarkus.native.additional-build-args=-march=compatibility
# Configures the Qpid JMS properties.
quarkus.qpid-jms.url=amqp://localhost:5672
quarkus.qpid-jms.username=admin
quarkus.qpid-jms.password=admin
# Topic Names
CASBIN_MODEL_CREATE_TOPIC=eu.nebulouscloud.ui.policies.model.upsert
CASBIN_MODEL_DELETE_TOPIC=eu.nebulousclous.ui.policies.model.delete
CASBIN_MODEL_GET_ALL_TOPIC=eu.nebulousclous.ui.policies.model.read
CASBIN_POLICY_CREATE_TOPIC=eu.nebulouscloud.ui.policies.rule.upsert
CASBIN_POLICY_DELETE_TOPIC=eu.nebulouscloud.ui.policies.rule.delete
CASBIN_POLICY_GET_ALL_TOPIC=eu.nebulouscloud.ui.policies.rule.read
DEPLOYMENT_CREATE_TOPIC=eu.nebulousclous.ui.policies.deployment.create
DEPLOYMENT_DELETE_TOPIC=eu.nebulousclous.ui.policies.deployment.delete
DEPLOYMENT_GET_ALL_TOPIC=eu.nebulousclous.ui.policies.deployment.read

View File

@ -0,0 +1,5 @@
_ _ ___ ____
_ __ ___| |__ _ _| |/ _ \ _ _/ ___|
| '_ \ / _ \ '_ \| | | | | | | | | | \___ \
| | | | __/ |_) | |_| | | |_| | |_| |___) |
|_| |_|\___|_.__/ \__,_|_|\___/ \__,_|____/

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
cm5ldGVzMB4XDTIzMTEyODEwNDI0NloXDTMzMTEyNTEwNDI0NlowFTETMBEGA1UE
AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKPL
sywxKS97a6JaJrFamhDq4WDRW9Av2ykESI6IhcAHijhN7I3N5kTgi/t6LLGE4qt1
3PQVYnBljCJhu4cmbr9oo2lEC9hKshyhw6pTlazi1tHCST3G2QL6MYSTonQ6Aq6o
Q7YymbdnJcRWGEeVUZXw6uF9GKVeW5rueAXmrPkoW0S7/hq2GF1M2UqlmRVWDI87
NdA3cPHYa5OvM8UB4nBpGkW0zb/2PjrEJ4HwtHFFhzu3BLi7twG9U7dKtKqL4dB0
yeVRqDLPwfQABf4S2mOC8Z3OKumdqbOt+hp3n1rR40vvX3BBMaaeJG0gODOw6iyl
zYpYIYPY1OpUq3hvJgcCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
/wQFMAMBAf8wHQYDVR0OBBYEFP363To2BYU4DCKoY3AodvEFVQkTMBUGA1UdEQQO
MAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBAHdnLnFJiHe+jq7DPYGP
sJ9tsiapZLT4jzt+QMik/hi0UNLne9QT7gDPp9wVLpsfwnc1grmACjlxd/iFRGu9
y2sWZKo4L/JhMoO6I5QDWKWlBsj+QN0aobx8KX5EgU9QUpdZWZwAqNErkAJEWOwf
aiB44Bp/nIRSKkUADmPVA7cToD7CFkSa8Q43bq4YZe9KVR9EYCn3zsGT5FaJ3YzI
FpUjd+ocbFhSmWi0Ut0qLcnufHIHNgRSL+tNm9FSKLnjLquSgtlZwMA0NpMb4mPE
1q5jWbGySBciTzjkSkDMfmnyNrblJgkRTc0fii0fHinOnNVD099dnvqAadg2+HJN
Bw0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,6 @@
-- This file allow to write SQL commands that will be emitted in test and dev.
-- The commands are commented as their support depends of the database
-- insert into myentity (id, field) values(1, 'field-1');
-- insert into myentity (id, field) values(2, 'field-2');
-- insert into myentity (id, field) values(3, 'field-3');
-- alter sequence myentity_seq restart with 4;

View File

@ -0,0 +1,8 @@
package ubi.nebulous;
import io.quarkus.test.junit.QuarkusIntegrationTest;
@QuarkusIntegrationTest
class ExampleResourceIT extends ExampleResourceTest {
// Execute the same tests but in packaged mode.
}

View File

@ -0,0 +1,20 @@
package ubi.nebulous;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
class ExampleResourceTest {
@Test
void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello RESTEasy"));
}
}

View File

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