diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000000000000000000000000000000000..9a076e2288ef97a755bdae010e86fcc862c2cdea --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,372 @@ +pipeline { + agent { + node { + label 'ozgcloud-jenkins-build-agent-jdk21' + } + } + + environment { + RELEASE_REGEX = /\d+.\d+.\d+/ + SNAPSHOT_REGEX = /\d+.\d+.\d+-SNAPSHOT/ + FAILED_STAGE = "" + SH_SUCCESS_STATUS_CODE = 0 + ELSTER_TRANSFER_OPERATOR_NAME = 'ozgcloud-elster-transfer-operator' + } + + options { + timeout(time: 1, unit: 'HOURS') + disableConcurrentBuilds() + buildDiscarder(logRotator(numToKeepStr: '10')) + } + + stages { + stage('Check Version') { + steps { + script { + FAILED_STAGE = env.STAGE_NAME + def rootPom = readMavenPom file: 'pom.xml' + def rootVersion = rootPom.version + + if(isReleaseBranch()){ + if ( !isReleaseVersion([rootVersion])) { + error("Keine Release Version für Branch ${env.BRANCH_NAME}.") + } + } else { + if ( !isSnapshotVersion([rootVersion])) { + error("Keine Snapshot Version für Branch ${env.BRANCH_NAME}.") + } + } + } + } + } + + stage('Set Version') { + when { + not { + anyOf { + branch 'master' + branch 'release' + } + } + } + steps { + script { + FAILED_STAGE=env.STAGE_NAME + JAR_TAG = getPomVersion('pom.xml').replace("SNAPSHOT", "${env.BRANCH_NAME}-SNAPSHOT") + } + configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) { + sh "mvn -s $MAVEN_SETTINGS versions:set -DnewVersion=${JAR_TAG} -DprocessAllModules=true" + + } + } + } + stage('Build OzgCloud ELster-Transfer Operator') { + steps { + script { + FAILED_STAGE=env.STAGE_NAME + } + configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) { + sh 'mvn -s $MAVEN_SETTINGS clean install -Dmaven.wagon.http.retryHandler.count=3' + + script { + try { + if (env.BRANCH_NAME == 'master') { + withSonarQubeEnv('sonarqube-ozg-sh'){ + sh 'mvn -s $MAVEN_SETTINGS sonar:sonar' + } + } + } catch (Exception e) { + unstable("SonarQube failed") + } + } + } + } + } + + stage('Deploy to Nexus'){ + steps { + script { + FAILED_STAGE = env.STAGE_NAME + } + configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) { + sh 'mvn -s $MAVEN_SETTINGS -DskipTests deploy' + sh 'mvn -s $MAVEN_SETTINGS versions:revert' + } + } + } + + stage('Build Docker image') { + steps { + script { + FAILED_STAGE=env.STAGE_NAME + } + + configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) { + sh 'mvn -s $MAVEN_SETTINGS spring-boot:build-image -DskipTests -Dmaven.wagon.http.retryHandler.count=3' + } + } + } + + stage('Tag and Push Docker image') { + steps { + script { + FAILED_STAGE=env.STAGE_NAME + IMAGE_TAG = buildVersionName() + + tagAndPushDockerImage(ELSTER_TRANSFER_OPERATOR_NAME, IMAGE_TAG) + + if (isMasterBranch()) { + tagAndPushDockerImage(ELSTER_TRANSFER_OPERATOR_NAME, 'snapshot-latest') + + } + else if (isReleaseBranch()) { + tagAndPushDockerImage(ELSTER_TRANSFER_OPERATOR_NAME, 'latest') + } + } + } + } + + stage('Test, build and deploy Elster-Transfer-Operator Helm Chart') { + steps { + script { + FAILED_STAGE=env.STAGE_NAME + HELM_CHART_VERSION = buildVersionName() + + sh "./run_helm_test.sh" + + dir('src/main/helm') { + + sh "helm package --version=${HELM_CHART_VERSION} ." + + deployHelmChart(HELM_CHART_VERSION) + } + } + } + } + + + stage('Trigger Dev rollout') { + when { + branch 'master' + } + steps { + script { + FAILED_STAGE = env.STAGE_NAME + + doDevRollout() + } + } + } + + stage('Trigger Test rollout') { + when { + branch 'release' + } + steps { + script { + FAILED_STAGE = env.STAGE_NAME + + doTestRollout() + } + } + } + stage ('Deploy SBOM to DependencyTrack') { + steps { + script { + IMAGE_TAG = buildVersionName() + + configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) { + withCredentials([string(credentialsId: 'dependency-track-api-key', variable: 'API_KEY')]) { + + catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { + sh "mvn --no-transfer-progress -s $MAVEN_SETTINGS io.github.pmckeown:dependency-track-maven-plugin:upload-bom -Ddependency-track.apiKey=$API_KEY -Ddependency-track.projectVersion=${IMAGE_TAG} -Ddependency-track.dependencyTrackBaseUrl=https://dependency-track.ozg-sh.de" + } + } + } + } + } + } + } + post { + always{ + junit testResults: '**/target/surefire-reports/*.xml', skipPublishingChecks: true + } + failure { + script { + if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'release') { + sendFailureMessage() + } + } + } + } +} + + +Void deployHelmChart(String helmChartVersion) { + withCredentials([usernamePassword(credentialsId: 'jenkins-nexus-login', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]){ + + result = sh script: '''curl -u $USERNAME:$PASSWORD https://nexus.ozg-sh.de/service/rest/v1/components?repository=ozg-base-apps-snapshot -F file=@ozgcloud-elster-transfer-operator-'''+helmChartVersion+'''.tgz''', returnStdout: true + + if (result != '') { + error(result) + } + } +} + +String getHelmRepoUrl(){ + if (isReleaseBranch()) { + return "https://nexus.ozg-sh.de/service/rest/v1/components?repository=ozg-base-apps" + } + return "https://nexus.ozg-sh.de/service/rest/v1/components?repository=ozg-base-apps-snapshot" +} + +String validateBranchName(branchName) { + int maxLength = 30 + if (branchName.length() > maxLength) { + String originalBranchName = branchName + branchName = branchName.substring(0, maxLength) + echo "WARNING: Branch name '${originalBranchName}' exceeded ${maxLength} characters. " + + "It has been truncated to '${branchName}' for deployment purposes." + } + return branchName +} +String buildVersionName() { + if (env.BRANCH_NAME == 'release') { + return getPomVersion('pom.xml') + } + return "${getPomVersion('pom.xml')}-${validateBranchName(env.BRANCH_NAME)}-${env.GIT_COMMIT.take(7)}".replaceAll("_", "-") +} + +Boolean isMasterBranch() { + return env.BRANCH_NAME == 'master' +} + +Boolean isReleaseBranch() { + return env.BRANCH_NAME == 'release' +} + +String getElementAccessToken() { + withCredentials([string(credentialsId: 'element-login-json', variable: 'LOGIN_JSON')]) { + return readJSON ( text: sh (script: '''curl -XPOST -d \"$LOGIN_JSON\" https://matrix.ozg-sh.de/_matrix/client/v3/login''', returnStdout: true)).access_token + } +} + +Void doDevRollout() { + cloneGitopsRepo() + setNewOperatorVersion('dev') + pushNewGitopsVersion('dev') +} + +Void doTestRollout() { + cloneGitopsRepo() + setNewOperatorVersion('test') + pushNewGitopsVersion('test') +} + +Void setNewOperatorVersion(String environment) { + dir('gitops') { + updateElsterTransferOperatorVersions(environment) + } +} + +Void updateElsterTransferOperatorVersions(String environment){ + def envFile = getApplicationValues(environment, ELSTER_TRANSFER_OPERATOR_NAME) + def envVersions = readYaml file: envFile + + envVersions.ozgcloud_elster_transfer_operator.image.tag = IMAGE_TAG + envVersions.ozgcloud_elster_transfer_operator.helm.version = HELM_CHART_VERSION + + writeYaml file: envFile, data: envVersions, overwrite: true +} + + +String getApplicationValues(String environment, String valuesFileName) { + return "${environment}/application/values/${valuesFileName}-values.yaml" +} + +Void pushNewGitopsVersion(String environment) { + dir('gitops') { + if (!hasValuesFileChanged(environment)) { + return + } + + withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) { + sh "git add ${environment}/application/values/ozgcloud-elster-transfer-operator-values.yaml" + + sh "git commit -m 'jenkins rollout ${environment} ozgcloud operators version ${IMAGE_TAG}'" + sh 'git push https://${USER}:${TOKEN}@git.ozg-sh.de/ozgcloud-devops/gitops.git' + } + } +} + +Boolean hasValuesFileChanged(String environment) { + return sh (script: "git status | grep '${environment}/application/values/ozgcloud-elster-transfer-operator-values.yaml'", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer +} + +Void configureGit() { + final email = "jenkins@ozg-sh.de" + final name = "jenkins" + + dir("gitops") { + sh "git config user.email '${email}'" + sh "git config user.name '${name}'" + } +} + +Void cloneGitopsRepo() { + withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) { + sh 'git clone https://${USER}:${TOKEN}@git.ozg-sh.de/ozgcloud-devops/gitops.git' + } + + configureGit() +} + +Void tagAndPushDockerImage(String imageName, String newTag){ + withCredentials([usernamePassword(credentialsId: 'jenkins-nexus-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) { + sh 'docker login docker.ozg-sh.de -u ${USER} -p ${PASSWORD}' + + sh "docker tag docker.ozg-sh.de/${imageName}:build-latest docker.ozg-sh.de/${imageName}:${newTag}" + sh "docker push docker.ozg-sh.de/${imageName}:${newTag}" + } +} + +String getPomVersion(String pomFile){ + def pom = readMavenPom file: pomFile + + return pom.version +} + +Boolean isReleaseVersion(List versions) { + return matchRegexVersion(versions, RELEASE_REGEX) +} + +Boolean isSnapshotVersion(List versions) { + return matchRegexVersion(versions, SNAPSHOT_REGEX) +} + +Boolean matchRegexVersion(List versions, String regex) { + for (version in versions) { + if ( !(version ==~ regex) ) { + return false + } + } + + return true +} + +Void sendFailureMessage() { + def room = '' + def data = """{"msgtype":"m.text", \ + "body":"FachstelleServer: Build Failed. Stage: ${FAILED_STAGE} Build-ID: ${env.BUILD_NUMBER} Link: ${BLUE_OCEAN_URL}", \ + "format": "org.matrix.custom.html", \ + "formatted_body":"FachstelleServer: Build Failed. Stage: ${FAILED_STAGE} Build-ID: <a href='${BLUE_OCEAN_URL}'>${env.BUILD_NUMBER}</a>"}""" + + if (env.BRANCH_NAME == 'master') { + room = "!iQPAvQIiRwRpNOszjw:matrix.ozg-sh.de" + } + else if (env.BRANCH_NAME == 'release') { + room = "!oWZpUGTFsxkJIYNfYg:matrix.ozg-sh.de" + } + + sh "curl -XPOST -H 'authorization: Bearer ${getElementAccessToken()}' -d '${data}' https://matrix.ozg-sh.de/_matrix/client/v3/rooms/$room/send/m.room.message" +} diff --git a/README.md b/README.md index f8b29dbac8ee924ad91b29cf5910112e1418acd6..c48731195327f9c2e2dd9ecd7d5b230db0d3d6b5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -# ozgcloud-elster-transfer-operator - +# Ozgcloud-Elster-Transfer Operator Um die Mandantenfähigkeit des Elster-Transfer Service nutzen zu können, muss für jede Kommune ein Service User im Elster-Transfer angelegt werden. Hierfür soll ein neuer Operator für den Elster-Transfer entwickelt werden. Der Operator soll einen neuen Nutzer anlegen und die Logindaten in den Namespace der Kommune ablegen. \ No newline at end of file diff --git a/dependency-check-supressions.xml b/dependency-check-supressions.xml new file mode 100644 index 0000000000000000000000000000000000000000..db1350f8a83ff8c231b055286a017cd62152964f --- /dev/null +++ b/dependency-check-supressions.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + Ministerpräsidenten des Landes Schleswig-Holstein + Staatskanzlei + Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + + Lizenziert unter der EUPL, Version 1.2 oder - sobald + diese von der Europäischen Kommission genehmigt wurden - + Folgeversionen der EUPL ("Lizenz"); + Sie dürfen dieses Werk ausschließlich gemäß + dieser Lizenz nutzen. + Eine Kopie der Lizenz finden Sie hier: + + https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + + Sofern nicht durch anwendbare Rechtsvorschriften + gefordert oder in schriftlicher Form vereinbart, wird + die unter der Lizenz verbreitete Software "so wie sie + ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + ausdrücklich oder stillschweigend - verbreitet. + Die sprachspezifischen Genehmigungen und Beschränkungen + unter der Lizenz sind dem Lizenztext zu entnehmen. + +--> +<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd"> + <suppress> + <vulnerabilityName>CVE-DUMMY</vulnerabilityName> + </suppress> +</suppressions> \ No newline at end of file diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000000000000000000000000000000000000..bf138b0fb9ba70009283b2196d3653bfa3b7e375 --- /dev/null +++ b/lombok.config @@ -0,0 +1,31 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + +lombok.log.fieldName=LOG +lombok.log.slf4j.flagUsage = ERROR +lombok.log.log4j.flagUsage = ERROR +lombok.data.flagUsage = ERROR +lombok.nonNull.exceptionType = IllegalArgumentException +lombok.addLombokGeneratedAnnotation = true \ No newline at end of file diff --git a/mvnw b/mvnw new file mode 100755 index 0000000000000000000000000000000000000000..66df2854281f4cb6869e4830dd1a7abd1e946c18 --- /dev/null +++ b/mvnw @@ -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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# 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 "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000000000000000000000000000000000000..95ba6f54ac526de46248af840bab26f33f946b93 --- /dev/null +++ b/mvnw.cmd @@ -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 https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM 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% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..04f57152090fc10b69de0cbcc6b6830b13547052 --- /dev/null +++ b/pom.xml @@ -0,0 +1,119 @@ +<?xml version="1.0"?> +<!-- + + Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + Ministerpräsidenten des Landes Schleswig-Holstein + Staatskanzlei + Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + + Lizenziert unter der EUPL, Version 1.2 oder - sobald + diese von der Europäischen Kommission genehmigt wurden - + Folgeversionen der EUPL ("Lizenz"); + Sie dürfen dieses Werk ausschließlich gemäß + dieser Lizenz nutzen. + Eine Kopie der Lizenz finden Sie hier: + + https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + + Sofern nicht durch anwendbare Rechtsvorschriften + gefordert oder in schriftlicher Form vereinbart, wird + die unter der Lizenz verbreitete Software "so wie sie + ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + ausdrücklich oder stillschweigend - verbreitet. + Die sprachspezifischen Genehmigungen und Beschränkungen + unter der Lizenz sind dem Lizenztext zu entnehmen. + +--> +<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>de.ozgcloud.common</groupId> + <artifactId>ozgcloud-common-parent</artifactId> + <version>4.6.0</version> + <relativePath/> + </parent> + + <groupId>de.ozgcloud</groupId> + <artifactId>ozgcloud-operator-elster-transfer</artifactId> + <version>1.0.0-SNAPSHOT</version> + + <name>OzgCloud Operator Elster-Transfer</name> + <description>OzgCloud Operator Elster-Transfer</description> + <inceptionYear>2024</inceptionYear> + + + <properties> + <operator-sdk.version>5.6.0</operator-sdk.version> + <mustache.version>0.9.14</mustache.version> + <snakeyaml.version>2.0</snakeyaml.version> + + <squareup.okio.version>3.9.1</squareup.okio.version> + <spring-boot.build-image.imageName>docker.ozg-sh.de/ozgcloud-elster-transfer-operator:build-latest</spring-boot.build-image.imageName> + </properties> + + <dependencies> + + <!-- spring --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>io.javaoperatorsdk</groupId> + <artifactId>operator-framework-spring-boot-starter</artifactId> + <version>${operator-sdk.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-core</artifactId> + </dependency> + <!-- tools --> + <dependency> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + <version>${snakeyaml.version}</version> + </dependency> + <dependency> + <groupId>com.github.spullara.mustache.java</groupId> + <artifactId>compiler</artifactId> + <version>${mustache.version}</version> + </dependency> + <dependency> + <groupId>com.squareup.okio</groupId> + <artifactId>okio</artifactId> + <version>${squareup.okio.version}</version> + </dependency> + + <!-- test --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <exclusions> + <exclusion> + <groupId>org.junit.vintage</groupId> + <artifactId>junit-vintage-engine</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + + <distributionManagement> + <repository> + <id>ozg-nexus</id> + <name>ozg-releases</name> + <url>https://nexus.ozg-sh.de/repository/ozg-releases/</url> + </repository> + <snapshotRepository> + <id>ozg-snapshots-nexus</id> + <name>ozg-snapshots</name> + <url>https://nexus.ozg-sh.de/repository/ozg-snapshots/</url> + </snapshotRepository> + </distributionManagement> + +</project> diff --git a/run_helm_test.sh b/run_helm_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..200cdb810dfbd79a48d3246c7522ff81cd0b644b --- /dev/null +++ b/run_helm_test.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + +set -e + +helm template ./src/main/helm/ -f src/test/helm/helm-linter-values.yaml +helm lint -f src/test/helm/helm-linter-values.yaml ./src/main/helm/ +cd src/main/helm && helm unittest -f '../../test/helm/**/*test.yaml' . diff --git a/src/main/helm/Chart.yaml b/src/main/helm/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..84336ad28972a154d0baa36cce54caa3538af1ce --- /dev/null +++ b/src/main/helm/Chart.yaml @@ -0,0 +1,31 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +apiVersion: v2 +name: ozgcloud-elster-transfer-operator +description: OZG Cloud Elster-Transfer Operator +type: application +version: 0.0.0-MANAGED-BY-JENKINS +appVersion: "0.0.0-MANAGED-BY-JENKINS" +icon: https://simpleicons.org/icons/helm.svg \ No newline at end of file diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl new file mode 100644 index 0000000000000000000000000000000000000000..94704db3d944797dc66a192c9314adc1108d6de3 --- /dev/null +++ b/src/main/helm/templates/_helpers.tpl @@ -0,0 +1,58 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +{{/* error check 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec) */}} +{{/* Namespace */}} +{{- define "app.namespace" -}} +{{- if gt (len (.Release.Namespace)) 63 -}} +{{- fail (printf ".Release.Namespace %s ist zu lang (max. 63 Zeichen)" .Release.Namespace) -}} +{{- end -}} +{{ printf "%s" .Release.Namespace }} +{{- end -}} + + +{{- define "app.matchLabels" }} +app.kubernetes.io/name: {{ .Release.Name }} +app.kubernetes.io/namespace: {{ include "app.namespace" . }} +component: ozgclud-elster-transfer-operator +{{- end -}} + + +{{- define "app.getCustomList" -}} +{{- with (.Values.env).customList -}} +{{- if kindIs "map" . -}} +{{ include "app.dictToList" . }} +{{- else if kindIs "slice" . -}} +{{ . | toYaml }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "app.dictToList" -}} +{{- $customList := list -}} +{{- range $key, $value := . -}} +{{- $customList = append $customList (dict "name" $key "value" $value) }} +{{- end -}} +{{- $customList | toYaml -}} +{{- end -}} \ No newline at end of file diff --git a/src/main/helm/templates/crds/operator.ozgcloud.de_OzgElsterTransferUser.yaml b/src/main/helm/templates/crds/operator.ozgcloud.de_OzgElsterTransferUser.yaml new file mode 100644 index 0000000000000000000000000000000000000000..069dbdad721b2257ca022357379f6b0f3123c203 --- /dev/null +++ b/src/main/helm/templates/crds/operator.ozgcloud.de_OzgElsterTransferUser.yaml @@ -0,0 +1,67 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ozgcloudelstertransferusers.operator.ozgcloud.de +spec: + group: operator.ozgcloud.de + names: + kind: OzgCloudElsterTransferUser + listKind: OzgCloudElsterTransferUserList + plural: ozgcloudelstertransferusers + singular: ozgcloudelstertransferuser + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OzgCloudElsterTransferUser is the Schema for the elster-transfer API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the resource this + object represents. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Elster-Transfer User + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of Elster-Transfer User + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..da5afb45286767cacd8a9b7d41c9e2476a8a52c9 --- /dev/null +++ b/src/main/helm/templates/deployment.yaml @@ -0,0 +1,77 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }} + namespace: {{ include "app.namespace" . }} + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/namespace: {{ include "app.namespace" . }} + app.kubernetes.io/part-of: ozg + app.kubernetes.io/version: {{ .Chart.AppVersion }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +spec: + selector: + matchLabels: + {{- include "app.matchLabels" . | indent 6 }} + template: + metadata: + labels: + {{- include "app.matchLabels" . | indent 8 }} + spec: + serviceAccountName: ozgcloud-elster-transfer-operator-service-account + containers: + - name: ozgcloud-elster-transfer-operator + image: "{{ (.Values.image).repo }}/{{ (.Values.image).name }}:{{ coalesce (.Values.image).tag "latest" }}" + env: + - name: ETR_NAMESPACE + value: "{{ .Values.etrNamespace | default "elster-transfer" }}" + {{- with include "app.getCustomList" . }} +{{ . | indent 8 }} + {{- end }} + imagePullPolicy: Always + resources: + {{- with .Values.resources }} +{{ toYaml . | indent 10 }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: false + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + dnsConfig: {} + dnsPolicy: ClusterFirst + imagePullSecrets: + - name: {{ required "imagePullSecret must be set" .Values.imagePullSecret }} + restartPolicy: Always + diff --git a/src/main/helm/templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role.yaml b/src/main/helm/templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c505a6aeebea252ddb11d71d46101331ec064a50 --- /dev/null +++ b/src/main/helm/templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role.yaml @@ -0,0 +1,36 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: ozgcloud-elster-transfer-operator-user-read-write-role +rules: +- apiGroups: ["operator.ozgcloud.de"] + resources: + - ozgcloudelstertransferusers + - ozgcloudelstertransferusers/status + - ozgcloudelstertransferusers/finalizers + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] diff --git a/src/main/helm/templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_binding.yaml b/src/main/helm/templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_binding.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d04cf44d3213a2b8fcc390c1ca484f10480f359f --- /dev/null +++ b/src/main/helm/templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_binding.yaml @@ -0,0 +1,36 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ozgcloud-elster-transfer-operator-user-read-write-role-binding +subjects: +- kind: ServiceAccount + name: ozgcloud-elster-transfer-operator-service-account + namespace: {{ include "app.namespace" . }} +roleRef: + kind: ClusterRole + name: ozgcloud-elster-transfer-operator-user-read-write-role + apiGroup: rbac.authorization.k8s.io diff --git a/src/main/helm/templates/rbacs/service_account.yaml b/src/main/helm/templates/rbacs/service_account.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6e3aab4ecf629cc7d123ffb33db19344bfb9d72b --- /dev/null +++ b/src/main/helm/templates/rbacs/service_account.yaml @@ -0,0 +1,30 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ozgcloud-elster-transfer-operator-service-account + namespace: {{ include "app.namespace" . }} \ No newline at end of file diff --git a/src/main/helm/values.yaml b/src/main/helm/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c466957f8d19351b5088307f96e2a329774045bd --- /dev/null +++ b/src/main/helm/values.yaml @@ -0,0 +1,25 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + diff --git a/src/main/java/de/ozgcloud/operator/ElsterTransferOperatorApplication.java b/src/main/java/de/ozgcloud/operator/ElsterTransferOperatorApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..e3c06f158fcd2e087172051029ff67d18c16a87a --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/ElsterTransferOperatorApplication.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ElsterTransferOperatorApplication { + + public static void main(String[] args) { + SpringApplication.run(ElsterTransferOperatorApplication.class, args); + } +} diff --git a/src/main/java/de/ozgcloud/operator/ElsterTransferOperatorConfiguration.java b/src/main/java/de/ozgcloud/operator/ElsterTransferOperatorConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..541d8fb39639e1c4727860fbfcd989fcfca23e87 --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/ElsterTransferOperatorConfiguration.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator; + +import java.time.Duration; +import java.util.List; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.javaoperatorsdk.operator.Operator; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; + +@Configuration +public class ElsterTransferOperatorConfiguration { + + public static final Duration RECONCILER_RETRY_SECONDS = Duration.ofSeconds(20); + public static final Duration RECONCILER_RETRY_SECONDS_ON_ERROR = Duration.ofSeconds(60); + + @Bean(initMethod = "start", destroyMethod = "stop") + @SuppressWarnings("rawtypes") + Operator operator(List<Reconciler> controllers) { + var operator = new Operator(); + controllers.forEach(operator::register); + return operator; + } +} \ No newline at end of file diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/OzgCloudCustomResourceStatus.java b/src/main/java/de/ozgcloud/operator/elstertransfer/OzgCloudCustomResourceStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..6534dd0021eafc78c385421e12a5e9d7c51df995 --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/OzgCloudCustomResourceStatus.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer; + +public enum OzgCloudCustomResourceStatus { + OK, IN_PROGRESS, ERROR; +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/Constants.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..883044e402884e6b20b6c6ca332c507eab941573 --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/Constants.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; +public class Constants { + + public static final String CONFIG_MAP_NAME = "etr-user-config"; + public static final String USERS_KEY = "users.yaml"; + public static final String ELSTER_TRANSFER_USER_LOGIN_KEY = "login"; + public static final String ELSTER_TRANSFER_USER_PASSWORD_KEY = "password"; + public static final String USER_ROLE = "USER"; + public static final String ETR_DEPLOYMENT_NAME = "elster-transfer"; + public static final String MUK_USER_SECRET_NAME = "muk-user-secret"; + +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserList.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserList.java new file mode 100644 index 0000000000000000000000000000000000000000..01df63b7c88a8dcffa19bf58c21edd5c9154ca48 --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserList.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import lombok.Builder; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Builder +class OzgCloudElsterTransferConfigMapUserList { + + private static final String ELSTER_TRANSFER_USER_LOGIN_KEY = "login"; + private static final String ELSTER_TRANSFER_USER_ROLE_KEY = "rolle"; + private static final String ELSTER_TRANSFER_USER_CREDENTIALS_KEY = "credentials"; + private static final String ELSTER_TRANSFER_USER_GROUP_KEY = "gruppe"; + private static final String ELSTER_TRANSFER_USER_PASSWORTHASH_KEY = "passwortHash"; + + private List<Map<String, Object>> usersList; + + public OzgCloudElsterTransferConfigMapUserList(List<Map<String, Object>> usersList) { + this.usersList = new ArrayList<>(usersList); + } + + boolean existsUser(String login) { + return usersList.stream() + .anyMatch(existingUser -> login.equals(existingUser.get(ELSTER_TRANSFER_USER_LOGIN_KEY))); + } + + void addUserToList(String login, String passwordHash, String role) { + Map<String, Object> formattedUser = Map.of( + ELSTER_TRANSFER_USER_LOGIN_KEY, login, + ELSTER_TRANSFER_USER_ROLE_KEY, role, + ELSTER_TRANSFER_USER_CREDENTIALS_KEY, Map.of(ELSTER_TRANSFER_USER_PASSWORTHASH_KEY, passwordHash), + ELSTER_TRANSFER_USER_GROUP_KEY, login); + usersList.add(formattedUser); + } + + void removeDeleted(String userLogin) { + usersList.removeIf(userMap -> userLogin.equals(userMap.get(ELSTER_TRANSFER_USER_LOGIN_KEY))); + } + + public List<Map<String, Object>> getUsersList() { + return usersList; + } + +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUser.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUser.java new file mode 100644 index 0000000000000000000000000000000000000000..a07284b1b91c41f6920100b94f8dcfca62a039db --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUser.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +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.Kind; +import io.fabric8.kubernetes.model.annotation.Plural; +import io.fabric8.kubernetes.model.annotation.Singular; +import io.fabric8.kubernetes.model.annotation.Version; + +@Kind("OzgCloudElsterTransferUser") +@Group("operator.ozgcloud.de") +@Version("v1") +@Singular("ozgcloudelstertransferuser") +@Plural("ozgcloudelstertransferusers") +@SuppressWarnings("serial") +public class OzgCloudElsterTransferUser extends CustomResource<OzgCloudElsterTransferUserSpec, OzgCloudElsterTransferUserStatus> + implements Namespaced { +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserReconciler.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserReconciler.java new file mode 100644 index 0000000000000000000000000000000000000000..8202ae41ee54d9033b6eb66c034f0ee175fe76ab --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserReconciler.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import org.springframework.stereotype.Component; + +import de.ozgcloud.operator.ElsterTransferOperatorConfiguration; +import de.ozgcloud.operator.elstertransfer.OzgCloudCustomResourceStatus; +import io.javaoperatorsdk.operator.api.reconciler.Cleaner; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +@RequiredArgsConstructor +@ControllerConfiguration +@Component +public class OzgCloudElsterTransferUserReconciler implements Reconciler<OzgCloudElsterTransferUser>, Cleaner<OzgCloudElsterTransferUser> { + + private final OzgCloudElsterTransferUserService service; + + @Override + public UpdateControl<OzgCloudElsterTransferUser> reconcile(OzgCloudElsterTransferUser elsterTransferUser, + Context<OzgCloudElsterTransferUser> context) { + try { + String namespace = elsterTransferUser.getMetadata().getNamespace(); + + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + return UserUpdateControlBuilder.fromResource(elsterTransferUser) + .withStatus(OzgCloudCustomResourceStatus.OK) + .withMessage("Status: OK") + .withReschedule(ElsterTransferOperatorConfiguration.RECONCILER_RETRY_SECONDS) + .build(); + } catch (Exception e) { + LOG.warn("{} could not reconcile in namespace {}: {}.", elsterTransferUser.getMetadata().getName(), + elsterTransferUser.getMetadata().getNamespace(), e); + return UserUpdateControlBuilder.fromResource(elsterTransferUser) + .withStatus(OzgCloudCustomResourceStatus.ERROR) + .withMessage(e.getMessage()) + .withReschedule(ElsterTransferOperatorConfiguration.RECONCILER_RETRY_SECONDS_ON_ERROR) + .build(); + } + } + + @Override + public DeleteControl cleanup(OzgCloudElsterTransferUser user, Context<OzgCloudElsterTransferUser> context) { + LOG.info("{} cleanup...", user.getMetadata().getName()); + String namespace = user.getMetadata().getNamespace(); + + if (user.getSpec().isKeepAfterDelete()) { + LOG.info("keep data"); + return DeleteControl.defaultDelete(); + } + + try { + service.delete(user); + return DeleteControl.defaultDelete(); + } catch (Exception e) { + LOG.warn("{} could not delete: {}", namespace, e); + return DeleteControl.noFinalizerRemoval().rescheduleAfter(ElsterTransferOperatorConfiguration.RECONCILER_RETRY_SECONDS_ON_ERROR); + } + } + +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserRemoteService.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserRemoteService.java new file mode 100644 index 0000000000000000000000000000000000000000..ffe7d43ec2191ca5a1ce03d6394b4cb480e6d836 --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserRemoteService.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import java.util.Base64; +import java.util.Objects; + +import org.springframework.stereotype.Service; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapList; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.Resource; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service +class OzgCloudElsterTransferUserRemoteService { + + private final KubernetesClient client; + + public ConfigMap getConfigMap(String configmapNamespace, String configMapName) { + return getConfigMapNonNamespaceOperation(configmapNamespace).withName(configMapName).get(); + } + + public ConfigMap createConfigMap(String configmapNamespace, String configMapName) { + return getConfigMapNonNamespaceOperation(configmapNamespace).resource(buildConfigMap(configMapName)).create(); + } + + NonNamespaceOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> getConfigMapNonNamespaceOperation(String configmapNamespace) { + return client.configMaps().inNamespace(configmapNamespace); + } + + ConfigMap buildConfigMap(String configMapName) { + return new ConfigMapBuilder() + .withNewMetadata() + .withName(configMapName) + .endMetadata() + .build(); + } + + public void updateConfigMapData(ConfigMap configMap, String key, String data) { + configMap.getData().put(key, data); + getConfigMapNonNamespaceOperation(configMap.getMetadata().getNamespace()).resource(configMap).update(); + } + + public void restartDeployment(String namespace, String deploymentName) { + Resource<Deployment> deploymentResource = getDeploymentResource(namespace, deploymentName); + Deployment deployment = deploymentResource.get(); + + if (Objects.nonNull(deployment)) { + setRestartAt(deployment); + client.resource(deployment).update(); + } + } + + Resource<Deployment> getDeploymentResource(String namespace, String deploymentName) { + return client.apps().deployments().inNamespace(namespace).withName(deploymentName); + } + + void setRestartAt(Deployment deployment) { + deployment.getSpec().getTemplate().getMetadata().getAnnotations() + .put("kubectl.kubernetes.io/restartedAt", String.valueOf(System.currentTimeMillis())); + } + + public void createOrUpdateSecret(String namespace, String userPassword, String secretName) { + client.secrets().inNamespace(namespace).resource(buildUserSecret(namespace, userPassword, secretName)).createOrReplace(); + } + + Secret buildUserSecret(String namespace, String userPassword, String secretName) { + return new SecretBuilder() + .withNewMetadata() + .withName(secretName) + .endMetadata() + .addToData(Constants.ELSTER_TRANSFER_USER_LOGIN_KEY, getEncodedString(namespace.getBytes())) + .addToData(Constants.ELSTER_TRANSFER_USER_PASSWORD_KEY, getEncodedString(userPassword.getBytes())) + .build(); + } + + private String getEncodedString(byte[] bytes) { + return Base64.getEncoder().encodeToString(bytes); + } + +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserService.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserService.java new file mode 100644 index 0000000000000000000000000000000000000000..656e07c16803817a8e4b33f96eec147641f9bcb1 --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserService.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.crypto.bcrypt.BCrypt; +import org.springframework.stereotype.Service; +import org.yaml.snakeyaml.Yaml; + +import com.github.mustachejava.DefaultMustacheFactory; +import com.github.mustachejava.Mustache; +import com.github.mustachejava.MustacheFactory; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +@RequiredArgsConstructor +@Service +class OzgCloudElsterTransferUserService { + + private final OzgCloudElsterTransferUserRemoteService remoteService; + + @Value("${etr.namespace}") + private String etrNamespace; + + public void updateConfigMapAndRestartDeploymentAndCreateSecret(String namespace) { + LOG.info("Updating/Creating Configmap"); + if (!userExists(namespace, etrNamespace, Constants.CONFIG_MAP_NAME)) { + String userPassword = updateConfigMapAndGenerateUserPassword(namespace, etrNamespace, Constants.CONFIG_MAP_NAME); + LOG.info("Restarting Deployment"); + restartDeployment(etrNamespace, Constants.ETR_DEPLOYMENT_NAME); + LOG.info("Creating Secret"); + createOrUpdateSecret(namespace, userPassword, Constants.MUK_USER_SECRET_NAME); + + } + } + + public void delete(OzgCloudElsterTransferUser user) { + String namespace = user.getMetadata().getNamespace(); + if (!userExists(namespace, etrNamespace, Constants.CONFIG_MAP_NAME)) { + LOG.info("User not exists"); + return; + } + LOG.info("{} do cleanup...", user.getMetadata()); + deleteUser(namespace, Constants.CONFIG_MAP_NAME); + restartDeployment(etrNamespace, Constants.ETR_DEPLOYMENT_NAME); + } + + String updateConfigMapAndGenerateUserPassword(String namespace, String configmapNamespace, String configMapName) { + ConfigMap configMap = createOrGetConfigMap(configmapNamespace, configMapName); + String userPassword = generatePassword(); + String usersYaml = addUserToUserYaml(getUsersFromConfigMap(configMap), namespace, userPassword); + updateConfigMap(configMap, usersYaml); + return userPassword; + } + + ConfigMap createOrGetConfigMap(String configmapNamespace, String configMapName) { + ConfigMap configMap = getConfigMap(configmapNamespace, configMapName); + if (Objects.isNull(configMap)) { + LOG.debug("Creating ConfigMap '{}' in namespace '{}'", configMapName, configmapNamespace); + configMap = remoteService.createConfigMap(configmapNamespace, configMapName); + } + return configMap; + } + + ConfigMap getConfigMap(String configmapNamespace, String configMapName) { + return remoteService.getConfigMap(configmapNamespace, configMapName); + } + + String addUserToUserYaml(OzgCloudElsterTransferConfigMapUserList users, String namespace, String userPassword) { + // use namespace as user "login" and "group" + addNewUserToList(users, namespace, hashPassword(userPassword)); + String usersYaml = constructYamlEntries(users); + return usersYaml; + } + + void updateConfigMap(ConfigMap configMap, String usersYaml) { + remoteService.updateConfigMapData(configMap, Constants.USERS_KEY, usersYaml); + } + + void restartDeployment(String etrNamespace, String deploymentName) { + remoteService.restartDeployment(etrNamespace, deploymentName); + } + + boolean userExists(String userLogin, String configMapNamespace, String configMapName) { + ConfigMap configMap = getConfigMap(configMapNamespace, configMapName); + if (Objects.isNull(configMap)) { + return false; + } + OzgCloudElsterTransferConfigMapUserList users = getUsersFromConfigMap(configMap); + LOG.debug("userExists is '{}' in namespace '{}'", users.existsUser(userLogin), userLogin); + return users.existsUser(userLogin); + + } + + void deleteUser(String userLogin, String configMapName) { + ConfigMap configMap = getConfigMap(etrNamespace, configMapName); + + OzgCloudElsterTransferConfigMapUserList usersList = getUsersFromConfigMap(configMap); + usersList.removeDeleted(userLogin); + String updatedUsersYaml = constructYamlEntries(usersList); + + remoteService.updateConfigMapData(configMap, Constants.USERS_KEY, updatedUsersYaml); + LOG.info("User with login '{}' removed from configmap successfully", userLogin); + } + + void createOrUpdateSecret(String namespace, String userPassword, String secretName) { + remoteService.createOrUpdateSecret(namespace, userPassword, secretName); + LOG.info("Secret for user in namespace '{}' created successfully", namespace); + } + + OzgCloudElsterTransferConfigMapUserList getUsersFromConfigMap(ConfigMap configMap) { + String usersYaml = configMap.getData().get(Constants.USERS_KEY); + if (Objects.isNull(usersYaml) || usersYaml.isBlank()) { + LOG.debug("userYaml is empty"); + return new OzgCloudElsterTransferConfigMapUserList(new ArrayList<>()); + } + Map<String, Object> load = new Yaml().load(usersYaml); + List<Map<String, Object>> usersList = (List<Map<String, Object>>) load.get("users"); + return new OzgCloudElsterTransferConfigMapUserList(usersList); + } + + void addNewUserToList(OzgCloudElsterTransferConfigMapUserList usersList, String login, String passwordHash) { + usersList.addUserToList(login, passwordHash, Constants.USER_ROLE); + } + + String constructYamlEntries(OzgCloudElsterTransferConfigMapUserList userList) { + LOG.info("constructYamlEntries"); + List<Map<String, Object>> usersList = userList.getUsersList(); + StringBuilder usersYaml = new StringBuilder(); + usersYaml.append("fileFormat: 1\nusers:\n"); + + for (Map<String, Object> userEntry : usersList) { + usersYaml.append(getYamlForUser(userEntry)); + usersYaml.append(System.lineSeparator()); + } + return usersYaml.toString(); + } + + String getYamlForUser(Map<String, Object> userEntry) { + MustacheFactory mf = new DefaultMustacheFactory(); + Mustache mustache = mf.compile("users.tmpl"); + + StringWriter writer = new StringWriter(); + mustache.execute(writer, userEntry); + return writer.toString(); + } + + String generatePassword() { + return UUID.randomUUID().toString(); + } + + private String hashPassword(String password) { + return BCrypt.hashpw(password, BCrypt.gensalt()); + } + +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserSpec.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserSpec.java new file mode 100644 index 0000000000000000000000000000000000000000..b546fd235d4617975cd6d87d130b8477eda175aa --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserSpec.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class OzgCloudElsterTransferUserSpec { + + @JsonProperty("keep_after_delete") + private boolean keepAfterDelete; +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserStatus.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..1147891a535702e6d048ed883c83fd6b0a945b6f --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserStatus.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import de.ozgcloud.operator.elstertransfer.OzgCloudCustomResourceStatus; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class OzgCloudElsterTransferUserStatus { + + private OzgCloudCustomResourceStatus status; + + private String message; +} diff --git a/src/main/java/de/ozgcloud/operator/elstertransfer/user/UserUpdateControlBuilder.java b/src/main/java/de/ozgcloud/operator/elstertransfer/user/UserUpdateControlBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..00c4caab8b8b03a91a66795b58ed367545ced319 --- /dev/null +++ b/src/main/java/de/ozgcloud/operator/elstertransfer/user/UserUpdateControlBuilder.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import java.time.Duration; +import java.util.Optional; + +import de.ozgcloud.operator.elstertransfer.OzgCloudCustomResourceStatus; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; + +class UserUpdateControlBuilder { + + private OzgCloudElsterTransferUser resource; + + private OzgCloudCustomResourceStatus status; + private Optional<String> message = Optional.empty(); + + private boolean reschedule = false; + private Duration scheduleDuration; + + public UserUpdateControlBuilder(OzgCloudElsterTransferUser resource) { + this.resource = resource; + } + + public static UserUpdateControlBuilder fromResource(OzgCloudElsterTransferUser resource) { + return new UserUpdateControlBuilder(resource); + } + + public UserUpdateControlBuilder withStatus(OzgCloudCustomResourceStatus status) { + this.status = status; + return this; + } + + public UserUpdateControlBuilder withMessage(String message) { + this.message = Optional.ofNullable(message); + return this; + } + + public UserUpdateControlBuilder withReschedule(Duration duration) { + this.reschedule = true; + this.scheduleDuration = duration; + return this; + } + + public UpdateControl<OzgCloudElsterTransferUser> build() { + resource.setStatus(buildOzgCloudElsterTransferUserStatus()); + + return buildUpdateControl(); + } + + private OzgCloudElsterTransferUserStatus buildOzgCloudElsterTransferUserStatus() { + var userStatus = OzgCloudElsterTransferUserStatus.builder().status(status); + message.ifPresent(userStatus::message); + + return userStatus.build(); + } + + private UpdateControl<OzgCloudElsterTransferUser> buildUpdateControl() { + if (reschedule) { + return UpdateControl.updateStatus(resource).rescheduleAfter(scheduleDuration); + } + return UpdateControl.updateStatus(resource); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..7b2723abeeab0b79e11ad6b575d59721fc19bab4 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,25 @@ + +management: + server: + port: 8081 + health: + livenessState: + enabled: true + readinessState: + enabled: true + endpoint: + health: + group: + exploratory: + include: livenessState,readinessState,ping + show-details: always + probes: + enabled: true + prometheus: + enabled: true + endpoints: + web: + exposure: + include: "*" +etr: + namespace: "elster-transfer" \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..93213f612c66446c316d8c6adcfcec3a90b738a8 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + + <Appenders> + <Console name="LogInJSON" target="SYSTEM_OUT"> + <!-- <JsonLayout compact="true" properties="true" eventEol="true"></JsonLayout> --> + <JsonTemplateLayout + eventTemplateUri="classpath:EcsLayout.json" + maxStringLength="65536" /> + </Console> + </Appenders> + + <Loggers> + <Root level="INFO"> + <appender-ref ref="LogInJSON" /> + </Root> + </Loggers> +</configuration> \ No newline at end of file diff --git a/src/main/resources/users.tmpl b/src/main/resources/users.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..7e4b5c497b25ae2c44c523d0ed2a954bb8b17575 --- /dev/null +++ b/src/main/resources/users.tmpl @@ -0,0 +1 @@ + - { login: "{{login}}", rolle: "{{rolle}}", credentials: { passwortHash: "{{credentials.passwortHash}}" }, gruppe: "{{gruppe}}" } \ No newline at end of file diff --git a/src/test/helm/crds/operator.ozgcloud.de_OzgElsterTransferUsers_test.yaml b/src/test/helm/crds/operator.ozgcloud.de_OzgElsterTransferUsers_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..87df7642fb6e93feba27169e6ac071f5f8a61664 --- /dev/null +++ b/src/test/helm/crds/operator.ozgcloud.de_OzgElsterTransferUsers_test.yaml @@ -0,0 +1,75 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +suite: operator.ozgcloud.de_OzgCloudElsterTransferUsers test +templates: + - templates/crds/operator.ozgcloud.de_OzgElsterTransferUser.yaml +tests: + - it: should have apiVersion + asserts: + - equal: + path: apiVersion + value: apiextensions.k8s.io/v1 + - it: should have isKind of + asserts: + - isKind: + of: CustomResourceDefinition + + - it: should have metadata name + asserts: + - equal: + path: metadata.name + value: ozgcloudelstertransferusers.operator.ozgcloud.de + + - it: should have spec group + asserts: + - equal: + path: spec.group + value: operator.ozgcloud.de + - it: should have spec names kind + asserts: + - equal: + path: spec.names.kind + value: OzgCloudElsterTransferUser + - it: should have spec names listKind + asserts: + - equal: + path: spec.names.listKind + value: OzgCloudElsterTransferUserList + - it: should have spec names plural + asserts: + - equal: + path: spec.names.plural + value: ozgcloudelstertransferusers + - it: should have spec names singular + asserts: + - equal: + path: spec.names.singular + value: ozgcloudelstertransferuser + + - it: should have spec scope + asserts: + - equal: + path: spec.scope + value: Namespaced \ No newline at end of file diff --git a/src/test/helm/crds/operator.ozgcloud.de_OzgElsterTransferUsers_versions_test.yaml b/src/test/helm/crds/operator.ozgcloud.de_OzgElsterTransferUsers_versions_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ed1ef8f5cea8288367ce67a7411980b87ef3b567 --- /dev/null +++ b/src/test/helm/crds/operator.ozgcloud.de_OzgElsterTransferUsers_versions_test.yaml @@ -0,0 +1,120 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +suite: operator.ozgcloud.de_OzgCloudElsterTransferUsers versions v1 test +templates: + - templates/crds/operator.ozgcloud.de_OzgElsterTransferUser.yaml +tests: + - it: should have versions name + asserts: + - equal: + path: spec.versions[0].name + value: v1 + - it: should have versions schema description + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.description + value: OzgCloudElsterTransferUser is the Schema for the elster-transfer API + - it: should have versions schema type + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.type + value: object + + - it: should have versions schema apiVersion property type + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.apiVersion.type + value: string + - it: should have versions schema apiVersion property description + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.apiVersion.description + value: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + + - it: should have versions schema kind property type + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.kind.type + value: string + - it: should have versions schema kind property description + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.kind.description + value: 'Kind is a string value representing the resource this object represents. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + - it: should have versions schema metadata + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.metadata.type + value: object + + - it: should have versions schema spec description + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.spec.description + value: Spec defines the desired state of Elster-Transfer User + - it: should have versions schema spec type + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.spec.type + value: object + - it: should have versions schema spec preserve unknown fields + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.spec.x-kubernetes-preserve-unknown-fields + value: true + + - it: should have versions schema status description + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.status.description + value: Status defines the observed state of Elster-Transfer User + - it: should have versions schema status type + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.status.type + value: object + - it: should have versions schema status preserve unknown fields + asserts: + - equal: + path: spec.versions[0].schema.openAPIV3Schema.properties.status.x-kubernetes-preserve-unknown-fields + value: true + + - it: should have versions served + asserts: + - equal: + path: spec.versions[0].served + value: true + - it: should have versions storage + asserts: + - equal: + path: spec.versions[0].storage + value: true + - it: should have versions subresources statis + asserts: + - equal: + path: spec.versions[0].subresources.status + value: {} \ No newline at end of file diff --git a/src/test/helm/deployment_env_test.yaml b/src/test/helm/deployment_env_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..99c86d81964dd62c66c8896f1280b513c23c551b --- /dev/null +++ b/src/test/helm/deployment_env_test.yaml @@ -0,0 +1,88 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + + +suite: test environments +templates: + - templates/deployment.yaml +set: + imagePullSecret: "docker-secret" +tests: + - it: check customList as list + set: + env.customList: + - name: my_test_environment_name + value: "A test value" + - name: test_environment + value: "B test value" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: my_test_environment_name + value: "A test value" + - contains: + path: spec.template.spec.containers[0].env + content: + name: test_environment + value: "B test value" + - it: check customList as dict + set: + env.customList: + my_test_environment_name: "A test value" + test_environment: "B test value" + image: + name: hase + tag: latest + imagePullSecret: imagePullSecret + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: my_test_environment_name + value: "A test value" + - contains: + path: spec.template.spec.containers[0].env + content: + name: test_environment + value: "B test value" + + - it: should contain env ETR_NAMESPACE with default value + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ETR_NAMESPACE + value: "elster-transfer" + + - it: should set env ETR_NAMESPACE + set: + etrNamespace: "elster-transfer2" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ETR_NAMESPACE + value: "elster-transfer2" \ No newline at end of file diff --git a/src/test/helm/deployment_matchlabels_test.yaml b/src/test/helm/deployment_matchlabels_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..32c6a8ba44087bdbccd3673b3b82f36ce480f792 --- /dev/null +++ b/src/test/helm/deployment_matchlabels_test.yaml @@ -0,0 +1,45 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + + +suite: deployment matchlabels +release: + name: ozgcloud-elstertransfer-operator + namespace: by-helm-test +templates: + - templates/deployment.yaml +set: + imagePullSecret: "docker-secret" +tests: + - it: should have set kubernetes name + asserts: + - equal: + path: spec.selector.matchLabels["app.kubernetes.io/name"] + value: ozgcloud-elstertransfer-operator + - it: should have set kubernetes namespace + asserts: + - equal: + path: spec.selector.matchLabels["app.kubernetes.io/namespace"] + value: by-helm-test \ No newline at end of file diff --git a/src/test/helm/deployment_metadata_labels_test.yaml b/src/test/helm/deployment_metadata_labels_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f9675a5f4ea3a1d8ae6fccae46a4ce382223cb7f --- /dev/null +++ b/src/test/helm/deployment_metadata_labels_test.yaml @@ -0,0 +1,45 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + + +suite: deployment test metadata labels +release: + name: ozgcloud-elstertransfer-operator + namespace: by-helm-test +templates: + - templates/deployment.yaml +set: + imagePullSecret: "docker-secret" +tests: + - it: check default labels namespace + asserts: + - equal: + path: metadata.labels["app.kubernetes.io/namespace"] + value: by-helm-test + - it: check default labels name + asserts: + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: ozgcloud-elstertransfer-operator \ No newline at end of file diff --git a/src/test/helm/deployment_pull_secret_test.yaml b/src/test/helm/deployment_pull_secret_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a4bcf059ac6018067ee3e5b3e39fd167406d9000 --- /dev/null +++ b/src/test/helm/deployment_pull_secret_test.yaml @@ -0,0 +1,45 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + + +suite: deployment pull secret +release: + name: ozgcloud-elstertransfer-operator + namespace: by-helm-test +templates: + - deployment.yaml + +tests: + - it: should set imagePullSecret + set: + imagePullSecret: imagePullSecret + asserts: + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: imagePullSecret + - it: should fail tempalte with error message when not set + asserts: + - failedTemplate: + errorMessage: imagePullSecret must be set \ No newline at end of file diff --git a/src/test/helm/deployment_resources_test.yaml b/src/test/helm/deployment_resources_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ee0c755bccbf77a50c8ceb7adcc8e5407cc52a89 --- /dev/null +++ b/src/test/helm/deployment_resources_test.yaml @@ -0,0 +1,66 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + + +suite: deployment resources test +release: + name: afm-adapter +templates: + - templates/deployment.yaml +set: + imagePullSecret: "docker-secret" +tests: + - it: test resources + set: + resources: + limits: + cpu: "11m" + memory: "22Mi" + requests: + cpu: "33m" + memory: "44Mi" + asserts: + - equal: + path: spec.template.spec.containers[0].resources.limits.cpu + value: 11m + - equal: + path: spec.template.spec.containers[0].resources.limits.memory + value: 22Mi + - equal: + path: spec.template.spec.containers[0].resources.requests.cpu + value: 33m + - equal: + path: spec.template.spec.containers[0].resources.requests.memory + value: 44Mi + + - it: test empty resources + set: + image: + name: hase + tag: latest + asserts: + - isEmpty: + path: spec.template.spec.containers[0].resources + diff --git a/src/test/helm/deployment_test.yaml b/src/test/helm/deployment_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fe274fcfbc7d541eb0f657e989d4535be7f639f6 --- /dev/null +++ b/src/test/helm/deployment_test.yaml @@ -0,0 +1,49 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + + +suite: deployment test +release: + name: intelliform-adapter + namespace: by-helm-test +templates: + - deployment.yaml + +tests: + - it: validate image type and container image + set: + imagePullSecret: "docker-secret" + image: + name: hase + tag: latest + repo: docker.ozg-sh.de + asserts: + - isKind: + of: Deployment + - isAPIVersion: + of: apps/v1 + - equal: + path: spec.template.spec.containers[0].image + value: docker.ozg-sh.de/hase:latest diff --git a/src/test/helm/helm-linter-values.yaml b/src/test/helm/helm-linter-values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..facbeea76465f293365c89542e58e98d8f10459c --- /dev/null +++ b/src/test/helm/helm-linter-values.yaml @@ -0,0 +1,28 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + +elstertransfer: + namespace: elster-transfer + +imagePullSecret: image-pull-secret \ No newline at end of file diff --git a/src/test/helm/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_binding_test.yaml b/src/test/helm/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_binding_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ffa6e4c8592665c18158d887220c91a682099d70 --- /dev/null +++ b/src/test/helm/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_binding_test.yaml @@ -0,0 +1,59 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + +suite: ElsterTransfer user rbac test +release: + name: ozgcloud-elstertransfer-operator + namespace: test-namespace +templates: + - templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_binding.yaml +tests: + - it: test ClusterRoleBinding metadata + asserts: + - isKind: + of: ClusterRoleBinding + - isAPIVersion: + of: rbac.authorization.k8s.io/v1 + - equal: + path: metadata.name + value: ozgcloud-elster-transfer-operator-user-read-write-role-binding + + - it: test ClusterRoleBinding subject + asserts: + - contains: + path: subjects + content: + kind: ServiceAccount + name: ozgcloud-elster-transfer-operator-service-account + namespace: test-namespace + - it: test ClusterRoleBinding roleRef + asserts: + - equal: + path: roleRef + value: + kind: ClusterRole + name: ozgcloud-elster-transfer-operator-user-read-write-role + apiGroup: rbac.authorization.k8s.io + diff --git a/src/test/helm/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_test.yaml b/src/test/helm/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fb80c0af19343d6042c456b5c6dcff8ceb8437e4 --- /dev/null +++ b/src/test/helm/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role_test.yaml @@ -0,0 +1,62 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + +suite: ElsterTransfer user rbac test +release: + name: ozgcloud-elstertransfer-operator + namespace: test-namespace +templates: + - templates/rbacs/ozgcloud_elstertransfer_operator_user_read_write_role.yaml +tests: + + - it: test ClusterRole metadata + asserts: + - isKind: + of: ClusterRole + - isAPIVersion: + of: rbac.authorization.k8s.io/v1 + - equal: + path: metadata.name + value: ozgcloud-elster-transfer-operator-user-read-write-role + + - it: test ClusterRoleBinding rules + asserts: + - contains: + path: rules + content: + apiGroups: + - operator.ozgcloud.de + resources: + - ozgcloudelstertransferusers + - ozgcloudelstertransferusers/status + - ozgcloudelstertransferusers/finalizers + verbs: + - get + - list + - watch + - create + - update + - patch + - delete \ No newline at end of file diff --git a/src/test/helm/rbacs/service_account_test.yaml b/src/test/helm/rbacs/service_account_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5c6e43dc607a55f3d5fa674b1499034c541d61e5 --- /dev/null +++ b/src/test/helm/rbacs/service_account_test.yaml @@ -0,0 +1,43 @@ +# +# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den +# Ministerpräsidenten des Landes Schleswig-Holstein +# Staatskanzlei +# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +# +# Lizenziert unter der EUPL, Version 1.2 oder - sobald +# diese von der Europäischen Kommission genehmigt wurden - +# Folgeversionen der EUPL ("Lizenz"); +# Sie dürfen dieses Werk ausschließlich gemäß +# dieser Lizenz nutzen. +# Eine Kopie der Lizenz finden Sie hier: +# +# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +# +# Sofern nicht durch anwendbare Rechtsvorschriften +# gefordert oder in schriftlicher Form vereinbart, wird +# die unter der Lizenz verbreitete Software "so wie sie +# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +# ausdrücklich oder stillschweigend - verbreitet. +# Die sprachspezifischen Genehmigungen und Beschränkungen +# unter der Lizenz sind dem Lizenztext zu entnehmen. +# + + + +suite: ServiceAccount test +release: + name: ozgcloud-elstertransfer-operator + namespace: test-namespace +templates: + - templates/rbacs/service_account.yaml +tests: + - it: test metadata + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: ozgcloud-elster-transfer-operator-service-account + - equal: + path: metadata.namespace + value: test-namespace \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapFactory.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..3475586e24bd233d1877e2bd86dc0ff9abe44840 --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapFactory.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.core.io.ClassPathResource; + +import com.github.mustachejava.DefaultMustacheFactory; +import com.github.mustachejava.Mustache; +import com.github.mustachejava.MustacheFactory; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; + +public class OzgCloudElsterTransferConfigMapFactory { + + public static ConfigMap create() { + Map<String, String> userData = Map.of( + "login", "admin", + "role", "ADMIN", + "passwordHash", "$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a", + "group", "Administratoren" + ); + Map<String, String> data = new HashMap<>(); + data.put(Constants.USERS_KEY, getYamlContent(userData)); + return createConfigMap(data); + } + + static ConfigMap createConfigMap(Map<String, String> data) { + return new ConfigMapBuilder() + .withNewMetadata() + .withName(Constants.CONFIG_MAP_NAME) + .endMetadata() + .withData(data) + .build(); + } + + static String getYamlContent(Map<String, String> userData) { + MustacheFactory mf = new DefaultMustacheFactory(); + Mustache mustache = mf.compile("users.yaml"); + StringWriter writer = new StringWriter(); + mustache.execute(writer, userData); + return writer.toString(); + } + +} diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserListFactory.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserListFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..fb271feae5f6336832ff1bffd6c2c455598bd177 --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserListFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class OzgCloudElsterTransferConfigMapUserListFactory { + + public static List<Map<String, Object>> create() { + Map<String, Object> user1 = Map.of( + "login", "user1", + "rolle", "USER", + "gruppe", "user1", + "credentials", Map.of( + "passwortHash", "$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a")); + List<Map<String, Object>> usersList = Arrays.asList(user1); + return usersList; + } + +} diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserListTest.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserListTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2aadbaf64576892ce874dceccf0051b661ce0deb --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferConfigMapUserListTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import static org.assertj.core.api.Assertions.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class OzgCloudElsterTransferConfigMapUserListTest { + + private OzgCloudElsterTransferConfigMapUserList configMapUserList; + + @BeforeEach + void setUp() { + configMapUserList = new OzgCloudElsterTransferConfigMapUserList(OzgCloudElsterTransferConfigMapUserListFactory.create()); + } + + @Nested + class TestExistsUser { + @Test + void shouldReturnTrueWhenUserExists() { + assertThat(configMapUserList.existsUser("user1")).isTrue(); + } + + @Test + void shouldReturnFalseWhenUserDoesNotExist() { + assertThat(configMapUserList.existsUser("nonExistentUser")).isFalse(); + } + } + + @Nested + class TestAddUser { + @Test + void shouldAddUser() { + configMapUserList.addUserToList("newUser", "$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a", "USER"); + + assertThat(configMapUserList.existsUser("newUser")).isTrue(); + } + + @Test + void shouldAddUserWithCorrectInput() { + configMapUserList.addUserToList("newUser", "$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a", "USER"); + Map<String, Object> addedUser = configMapUserList.getUsersList() + .stream() + .filter(user -> "newUser".equals(user.get("login"))) + .findFirst() + .orElseThrow(); + + assertThat(addedUser.get("rolle")).isEqualTo("USER"); + assertThat(Map.of("passwortHash", "$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a")).isEqualTo(addedUser.get("credentials")); + assertThat("newUser").isEqualTo(addedUser.get("gruppe")); + } + } + + @Nested + class TestRemoveUser { + @Test + void shouldRemoveUserCorrectly() { + configMapUserList.removeDeleted("user1"); + + assertThat(configMapUserList.existsUser("user1")).isFalse(); + } + } + + @Nested + class TestGetUsersList { + + @Test + void shouldReturnCurrentUsersList() { + List<Map<String, Object>> userList = configMapUserList.getUsersList(); + Map<String, Object> user = userList.get(0); + + assertThat(userList).hasSize(1); + assertThat(user.get("gruppe")).isEqualTo("user1"); + assertThat(user.get("login")).isEqualTo("user1"); + assertThat(user.get("rolle")).isEqualTo("USER"); + assertThat(user.get("credentials")).isEqualTo(Map.of("passwortHash", "$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a")); + assertThat(user.get("gruppe")).isEqualTo("user1"); + } + + @Test + void shouldReturnEmptyListIfNoUsers() { + OzgCloudElsterTransferConfigMapUserList emptyConfigMapUserList = new OzgCloudElsterTransferConfigMapUserList(new ArrayList<>()); + + assertThat(emptyConfigMapUserList.getUsersList()).isEmpty(); + } + } +} diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferStatusTestFactory.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferStatusTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..35f3d810d7e5d1c588d192ba90345b84ba338399 --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferStatusTestFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +public class OzgCloudElsterTransferStatusTestFactory { + + public static OzgCloudElsterTransferUserStatus create() { + return createBuilder().build(); + } + + public static OzgCloudElsterTransferUserStatus.OzgCloudElsterTransferUserStatusBuilder createBuilder() { + return OzgCloudElsterTransferUserStatus.builder(); + } +} diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserReconcilerTest.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserReconcilerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9c8a513a81f97fea978f2caeef82fa9f502552ab --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserReconcilerTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import de.ozgcloud.operator.ElsterTransferOperatorConfiguration; +import de.ozgcloud.operator.elstertransfer.OzgCloudCustomResourceStatus; +import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; + +class OzgCloudElsterTransferUserReconcilerTest { + + @Spy + @InjectMocks + private OzgCloudElsterTransferUserReconciler reconciler; + + @Mock + private OzgCloudElsterTransferUserService service; + + @DisplayName("Reconcile") + @Nested + class TestReconcile { + private final OzgCloudElsterTransferUser user = OzgCloudElsterTransferUserTestFactory.create(); + + @Test + void shouldCallUpdateConfigMap() { + reconciler.reconcile(user, null); + + verify(service).updateConfigMapAndRestartDeploymentAndCreateSecret(OzgCloudElsterTransferUserTestFactory.METADATA_NAMESPACE); + } + + @Test + void shouldReturnUpdateControl() { + var response = reconciler.reconcile(OzgCloudElsterTransferUserTestFactory.create(), null); + + assertThat(response.getResource()).isNotNull(); + } + + + @Test + void shouldSetStatusOk() { + var response = reconciler.reconcile(OzgCloudElsterTransferUserTestFactory.create(), null); + + assertThat(response.getResource().getStatus().getStatus()).isEqualTo(OzgCloudCustomResourceStatus.OK); + } + + @Test + void shouldRescheduleOnError() { + doThrow(RuntimeException.class).when(service) + .updateConfigMapAndRestartDeploymentAndCreateSecret(OzgCloudElsterTransferUserTestFactory.METADATA_NAMESPACE); + + var response = reconciler.reconcile(user, null); + + assertThat(response.getResource().getStatus().getStatus()).isEqualTo(OzgCloudCustomResourceStatus.ERROR); + } + + + + } + + @DisplayName("Cleanup") + @Nested + class TestReconcilerCleanup { + + private final OzgCloudElsterTransferUser user = OzgCloudElsterTransferUserTestFactory.create(); + + @Test + void shouldCallServiceDelete() { + reconciler.cleanup(user, null); + + verify(service).delete(user); + } + + @Test + void shouldReturnDeleteControlIfErrorNotThrow() { + var control = reconciler.cleanup(user, null); + + assertThat(control).usingRecursiveComparison().isEqualTo(DeleteControl.defaultDelete()); + } + + @Test + void shouldRescheduleOnError() { + doThrow(RuntimeException.class).when(service) + .delete(user); + + var control = reconciler.cleanup(user, null); + + assertThat(control).usingRecursiveComparison() + .isEqualTo(DeleteControl.noFinalizerRemoval().rescheduleAfter(ElsterTransferOperatorConfiguration.RECONCILER_RETRY_SECONDS_ON_ERROR)); + } + + } + +} diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserRemoteServiceTest.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserRemoteServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7e8f0aa875def2ade364546d440901b541441476 --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserRemoteServiceTest.java @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapList; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.api.model.SecretList; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentList; +import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.AppsAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.kubernetes.client.dsl.NamespaceableResource; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.RollableScalableResource; + +class OzgCloudElsterTransferUserRemoteServiceTest { + + @Mock + private KubernetesClient client; + + @Mock + private AppsAPIGroupDSL appsAPIGroupDSL; + + @Spy + @InjectMocks + private OzgCloudElsterTransferUserRemoteService remoteService; + + @Mock + private MixedOperation<Deployment, DeploymentList, RollableScalableResource<Deployment>> deploymentOperation; + + @Mock + private RollableScalableResource<Deployment> deploymentResource; + + @Mock + private MixedOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> configMapOperation; + + @Mock + private NonNamespaceOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> nonNamespaceOperation; + + @Mock + private Resource<ConfigMap> configMapResource; + + @Mock + private MixedOperation<Secret, SecretList, Resource<Secret>> secretOperation; + + @Mock + private Resource<Secret> secretResource; + + @Mock + private NamespaceableResource<Secret> namespaceableSecret; + + @Mock + private NamespaceableResource<Deployment> namespaceableDeployment; + + private static final String namespace = OzgCloudElsterTransferUserTestFactory.METADATA_NAMESPACE; + private static final String configMapName = Constants.CONFIG_MAP_NAME; + private static final String deploymentName = Constants.ETR_DEPLOYMENT_NAME; + private static final String secretName = Constants.MUK_USER_SECRET_NAME; + private static final String configmapNamespace = "elster-transfer"; + private static final String userPassword = "userPassword"; + + @DisplayName("test ConfigMap") + @Nested + class TestConfigMap { + @BeforeEach + void init() { + lenient().when(client.configMaps()).thenReturn(configMapOperation); + lenient().when(configMapOperation.inNamespace(configmapNamespace)).thenReturn(nonNamespaceOperation); + } + + @DisplayName("get configMap") + @Nested + class TestGetConfigMap { + @Test + void shouldCallGetConfigMapNonNamespaceOperation() { + when(nonNamespaceOperation.withName(configMapName)).thenReturn(configMapResource); + ConfigMap configMap = new ConfigMapBuilder() + .withNewMetadata() + .withName(configMapName) + .endMetadata() + .build(); + when(configMapResource.get()).thenReturn(configMap); + + remoteService.getConfigMap(configmapNamespace, configMapName); + + verify(remoteService).getConfigMapNonNamespaceOperation(configmapNamespace); + } + + @Test + void shouldCallWithNameGet() { + when(nonNamespaceOperation.withName(configMapName)).thenReturn(configMapResource); + ConfigMap configMap = new ConfigMapBuilder() + .withNewMetadata() + .withName(configMapName) + .endMetadata() + .build(); + when(configMapResource.get()).thenReturn(configMap); + + remoteService.getConfigMap(configmapNamespace, configMapName); + + verify(nonNamespaceOperation.withName(configMapName)).get(); + } + + @Test + void shouldGetConfigMap() { + when(nonNamespaceOperation.withName(configMapName)).thenReturn(configMapResource); + ConfigMap configMap = new ConfigMapBuilder() + .withNewMetadata() + .withName(configMapName) + .endMetadata() + .build(); + when(configMapResource.get()).thenReturn(configMap); + + ConfigMap result = remoteService.getConfigMap(configmapNamespace, configMapName); + + assertThat(result.getMetadata().getName()).isEqualTo(configMapName); + } + + @DisplayName("getConfigMapNonNamespaceOperation") + @Nested + class TestgetConfigMapNonNamespaceOperation { + + @Test + void shouldCallInNamespace() { + when(client.configMaps().inNamespace(configmapNamespace)).thenReturn(nonNamespaceOperation); + + remoteService.getConfigMapNonNamespaceOperation(configmapNamespace); + + verify(client.configMaps()).inNamespace(configmapNamespace); + } + + @Test + void shouldReturnConfigMapNonNamespaceOperation() { + when(client.configMaps().inNamespace(configmapNamespace)).thenReturn(nonNamespaceOperation); + + NonNamespaceOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> result = remoteService + .getConfigMapNonNamespaceOperation(configmapNamespace); + + assertThat(nonNamespaceOperation).isEqualTo(result); + } + } + } + + @DisplayName("create configmap") + @Nested + class TestCreateConfigMap { + + ConfigMap configMap; + + @BeforeEach + void init() { + lenient().when(nonNamespaceOperation.resource(any(ConfigMap.class))).thenReturn(configMapResource); + configMap = new ConfigMapBuilder() + .withNewMetadata() + .withName(configMapName) + .endMetadata() + .build(); + } + + @Test + void shouldCreateConfigMap() { + when(configMapResource.create()).thenReturn(configMap); + when(configMapResource.create()).thenReturn(configMap); + + ConfigMap result = remoteService.createConfigMap(configmapNamespace, configMapName); + + assertThat(result.getMetadata().getName()).isEqualTo(configMapName); + } + + @Test + void shouldCallGetConfigMapNonNamespaceOperation() { + remoteService.createConfigMap(configmapNamespace, configMapName); + + verify(remoteService).getConfigMapNonNamespaceOperation(configmapNamespace); + } + + @Test + void shouldCallResourceCreate() { + remoteService.createConfigMap(configmapNamespace, configMapName); + + verify(nonNamespaceOperation.resource(configMap)).create(); + } + + @DisplayName("ConfigMapBuilderTest") + @Nested + class TestConfigMapBuilder { + + @Test + void shouldBuildConfigMap() { + ConfigMap result = remoteService.buildConfigMap(configMapName); + + assertThat(result.getMetadata()).isNotNull(); + assertThat(configMapName).isEqualTo(result.getMetadata().getName()); + } + } + } + + @DisplayName("update configmap") + @Nested + class TestUpdateConfigMap { + ConfigMap configMap = new ConfigMap(); + String key = "test-key"; + String data = "new-data"; + + @BeforeEach + void init() { + when(nonNamespaceOperation.resource(any(ConfigMap.class))).thenReturn(configMapResource); + when(configMapResource.update()).thenReturn(configMap); + + configMap.setMetadata(new io.fabric8.kubernetes.api.model.ObjectMeta()); + configMap.getMetadata().setNamespace(configmapNamespace); + } + + @Test + void shouldCallGetConfigMapNonNamespaceOperation() { + remoteService.updateConfigMapData(configMap, key, data); + + verify(remoteService).getConfigMapNonNamespaceOperation(configmapNamespace); + } + + @Test + void shouldCallResourceUpdate() { + remoteService.updateConfigMapData(configMap, key, data); + + verify(nonNamespaceOperation.resource(configMap)).update(); + } + + @Test + void shouldUpdateConfigMapData() { + remoteService.updateConfigMapData(configMap, key, data); + + assertThat(configMap.getData()).containsKey(key); + assertThat(configMap.getData().get(key)).isEqualTo(data); + } + } + + } + + @DisplayName("restart deployment") + @Nested + class TestRestartDeployment { + Deployment deployment = new Deployment(); + + @BeforeEach + void setUp() { + deployment.setSpec(new DeploymentSpec()); + deployment.getSpec().setTemplate(new PodTemplateSpec()); + deployment.getSpec().getTemplate().setMetadata(new ObjectMeta()); + } + + @DisplayName("update deployment") + @Nested + class TestUpdateDeployment { + + @BeforeEach + void setUp() { + when(client.apps()).thenReturn(appsAPIGroupDSL); + when(appsAPIGroupDSL.deployments()).thenReturn(deploymentOperation); + when(deploymentOperation.inNamespace(anyString())).thenReturn(deploymentOperation); + when(deploymentOperation.withName(anyString())).thenReturn(deploymentResource); + } + + @Test + void shouldCallUpdateDeployment() { + when(deploymentResource.get()).thenReturn(deployment); + when(client.resource(deployment)).thenReturn(namespaceableDeployment); + + remoteService.restartDeployment(namespace, deploymentName); + + verify(client.resource(deployment)).update(); + + } + + @Test + void shouldCallSetRestartAt() { + when(deploymentResource.get()).thenReturn(deployment); + when(client.resource(deployment)).thenReturn(namespaceableDeployment); + + remoteService.restartDeployment(namespace, deploymentName); + + verify(remoteService).setRestartAt(deployment); + } + + @Test + void shouldCallGetDeployment() { + remoteService.restartDeployment(namespace, deploymentName); + + verify(deploymentResource).get(); + } + + @Test + void shouldCallGetDeploymentResource() { + remoteService.restartDeployment(namespace, deploymentName); + + verify(remoteService).getDeploymentResource(namespace, deploymentName); + } + + } + + @DisplayName("set restart flag") + @Nested + class TestsetRestartAt { + @Test + void shouldSetRestartedAtAnnotation() { + Map<String, String> annotations = new HashMap<>(); + deployment.getSpec().getTemplate().getMetadata().setAnnotations(annotations); + + remoteService.setRestartAt(deployment); + + assertThat(annotations).containsKey("kubectl.kubernetes.io/restartedAt"); + assertThat(annotations.get("kubectl.kubernetes.io/restartedAt")).isNotNull(); + } + } + + @DisplayName("getDeploymentResource") + @Nested + class TestGetDeploymentResource { + @Test + void shouldGetDeploymentResource() { + when(client.apps()).thenReturn(appsAPIGroupDSL); + when(appsAPIGroupDSL.deployments()).thenReturn(deploymentOperation); + when(deploymentOperation.inNamespace(anyString())).thenReturn(deploymentOperation); + when(deploymentOperation.withName(anyString())).thenReturn(deploymentResource); + + Resource<Deployment> result = remoteService.getDeploymentResource(namespace, deploymentName); + + assertThat(result).isEqualTo(deploymentResource); + } + + @Test + void shouldCallAppsDeploymentsInNamespaceWithName() { + when(client.apps()).thenReturn(appsAPIGroupDSL); + when(appsAPIGroupDSL.deployments()).thenReturn(deploymentOperation); + when(deploymentOperation.inNamespace(anyString())).thenReturn(deploymentOperation); + when(deploymentOperation.withName(anyString())).thenReturn(deploymentResource); + + remoteService.getDeploymentResource(namespace, deploymentName); + + verify(client).apps(); + verify(client.apps()).deployments(); + verify(client.apps().deployments()).inNamespace(namespace); + verify(client.apps().deployments().inNamespace(namespace)).withName(deploymentName); + } + + } + } + + @DisplayName("createOrUpdateSecret") + @Nested + class TestCreateOrUpdateSecret { + Secret secret; + + @BeforeEach + void setUp() { + secret = new SecretBuilder() + .withNewMetadata() + .withName(secretName) + .endMetadata() + .addToData("login", Base64.getEncoder().encodeToString(namespace.getBytes())) + .addToData("password", Base64.getEncoder().encodeToString(userPassword.getBytes())) + .build(); + } + + @Test + void shouldCallBuildUserSecret() { + when(client.secrets()).thenReturn(secretOperation); + when(secretOperation.inNamespace(anyString())).thenReturn(secretOperation); + when(secretOperation.resource(any(Secret.class))).thenReturn(secretResource); + + remoteService.createOrUpdateSecret(namespace, userPassword, secretName); + + verify(remoteService).buildUserSecret(namespace, userPassword, secretName); + } + + @Test + void shouldCallServerSideApply() { + when(client.secrets()).thenReturn(secretOperation); + when(secretOperation.inNamespace(anyString())).thenReturn(secretOperation); + when(secretOperation.resource(any(Secret.class))).thenReturn(secretResource); + + remoteService.createOrUpdateSecret(namespace, userPassword, secretName); + + verify(client.secrets().inNamespace(namespace).resource(secret)).createOrReplace(); + } + + @DisplayName("buildUserSecret") + @Nested + class TestBuildUserSecret { + + @Test + void shouldCallCreateOrUpdateSecret() { + Secret secret = remoteService.buildUserSecret(namespace, userPassword, secretName); + + assertThat(secret.getMetadata()).isNotNull(); + assertThat(secretName).isEqualTo(secret.getMetadata().getName()); + assertThat(secret.getData().containsKey(Constants.ELSTER_TRANSFER_USER_LOGIN_KEY)).isTrue(); + assertThat(secret.getData().containsKey(Constants.ELSTER_TRANSFER_USER_PASSWORD_KEY)).isTrue(); + assertThat(secret.getData().get(Constants.ELSTER_TRANSFER_USER_LOGIN_KEY)) + .isEqualTo(Base64.getEncoder().encodeToString(namespace.getBytes())); + assertThat(secret.getData().get(Constants.ELSTER_TRANSFER_USER_PASSWORD_KEY)) + .isEqualTo(Base64.getEncoder().encodeToString(userPassword.getBytes())); + } + } + } + +} diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserServiceTest.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1439d44af50df50cfed74c0e1c66cb66bc0d43f4 --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserServiceTest.java @@ -0,0 +1,614 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.test.util.ReflectionTestUtils; + +import io.fabric8.kubernetes.api.model.ConfigMap; + +class OzgCloudElsterTransferUserServiceTest { + + @Mock + private OzgCloudElsterTransferUserRemoteService remoteService; + + @Spy + @InjectMocks + private OzgCloudElsterTransferUserService service; + + @Mock + private ConfigMap configMap; + + @Mock + private OzgCloudElsterTransferConfigMapUserList users; + + private static final String namespace = OzgCloudElsterTransferUserTestFactory.METADATA_NAMESPACE; + private static final String configMapName = Constants.CONFIG_MAP_NAME; + private static final String deploymentName = Constants.ETR_DEPLOYMENT_NAME; + private static final String secretName = Constants.MUK_USER_SECRET_NAME; + private static final String configMapNamespace = "elster-transfer"; + private static final String usersKey = Constants.USERS_KEY; + private static final String userPassword = "userPassword"; + + @Nested + class TestUpdateConfigMapAndRestartDeploymentAndCreateSecret { + + @BeforeEach + void setUp() { + configMap = OzgCloudElsterTransferConfigMapFactory.create(); + lenient().when(remoteService.getConfigMap(anyString(), + anyString())).thenReturn(configMap); + ReflectionTestUtils.setField(service, "etrNamespace", "elster-transfer"); + } + + @Test + void shouldCallUserExists() { + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + verify(service).userExists(namespace, configMapNamespace, configMapName); + } + + @Test + void shouldCallupdateConfigMapAndGenerateUserPasswordIfUserNotExists() { + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + verify(service).updateConfigMapAndGenerateUserPassword(namespace, + configMapNamespace, configMapName); + } + + @Test + void shouldCallRestartDeploymentIfUserNotExists() { + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + verify(service).restartDeployment(configMapNamespace, deploymentName); + } + + @Test + void shouldCallCreateOrUpdateSecretIfUserNotExists() { + when(service.updateConfigMapAndGenerateUserPassword(namespace, + configMapNamespace, configMapName)).thenReturn(userPassword); + + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + verify(service).createOrUpdateSecret(namespace, userPassword, secretName); + } + + @Test + void shouldNotCallRestartDeploymentIfUserExists() { + when(service.userExists(namespace, configMapNamespace, configMapName)).thenReturn(true); + + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + verify(service, never()).restartDeployment(any(), any()); + } + + @Test + void shouldNotCallUpdateConfigMapAndGenerateUserPasswordIfUserExists() { + when(service.userExists(namespace, configMapNamespace, configMapName)).thenReturn(true); + + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + verify(service, never()).updateConfigMapAndGenerateUserPassword(any(), any(), any()); + } + + @Test + void shouldNotCallCreateOrUpdateSecretIfUserExists() { + when(service.userExists(namespace, configMapNamespace, configMapName)).thenReturn(true); + + service.updateConfigMapAndRestartDeploymentAndCreateSecret(namespace); + + verify(service, never()).createOrUpdateSecret(any(), any(), any()); + } + + @Nested + class TestUpdateConfigMapAndGenerateUserPassword { + + @Test + void shouldCallCreateOrGetConfigMap() { + service.updateConfigMapAndGenerateUserPassword(namespace, configMapNamespace, configMapName); + + verify(service).createOrGetConfigMap(configMapNamespace, configMapName); + } + + @Test + void shouldCallGeneratePassword() { + service.updateConfigMapAndGenerateUserPassword(namespace, configMapNamespace, configMapName); + + verify(service).generatePassword(); + } + + @Test + void shouldCallAddUserToUserYaml() { + service.updateConfigMapAndGenerateUserPassword(namespace, configMapNamespace, configMapName); + + verify(service).addUserToUserYaml(any(), any(), any()); + } + + @Test + void shouldCallGetUsersFromConfigMap() { + when(service.createOrGetConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + + service.updateConfigMapAndGenerateUserPassword(namespace, configMapNamespace, configMapName); + + verify(service).getUsersFromConfigMap(configMap); + } + + @Test + void shouldCallUpdateConfigMap() { + String usersYaml = "usersYaml"; + when(service.createOrGetConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + when(service.generatePassword()).thenReturn(userPassword); + when(service.addUserToUserYaml(users, namespace, userPassword)).thenReturn(usersYaml); + when(service.getUsersFromConfigMap(configMap)).thenReturn(users); + + service.updateConfigMapAndGenerateUserPassword(namespace, configMapNamespace, configMapName); + + verify(service).updateConfigMap(configMap, usersYaml); + } + + @Test + void shouldReturnUserPassword() { + when(service.generatePassword()).thenReturn(userPassword); + + String result = service.updateConfigMapAndGenerateUserPassword(namespace, configMapNamespace, configMapName); + + assertThat(result).isEqualTo(userPassword); + } + + @Nested + class TestCreateOrGetConfigMap { + + @Test + void shouldCallGetConfigMap() { + service.createOrGetConfigMap(configMapNamespace, configMapName); + + verify(service).getConfigMap(configMapNamespace, configMapName); + } + + @Test + void shouldCallCreateConfigMap() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(null); + + service.createOrGetConfigMap(configMapNamespace, configMapName); + + verify(remoteService).createConfigMap(configMapNamespace, configMapName); + } + + @Test + void shouldCreateConfigMap() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(null); + when(remoteService.createConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + + ConfigMap result = service.createOrGetConfigMap(configMapNamespace, configMapName); + + assertThat(result).isEqualTo(configMap); + + } + + @Test + void shouldNotCallCreateConfigMap() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + + service.createOrGetConfigMap(configMapNamespace, configMapName); + + verify(remoteService, never()).createConfigMap(any(), any()); + } + + @Nested + class TestGetConfigMap { + + @Test + void shouldCallGetConfigMap() { + service.getConfigMap(configMapNamespace, configMapName); + + verify(remoteService).getConfigMap(configMapNamespace, configMapName); + } + + @Test + void shouldReturnConfigMap() { + when(remoteService.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + + ConfigMap result = service.getConfigMap(configMapNamespace, configMapName); + + assertThat(result).isEqualTo(configMap); + } + + } + + } + + @Nested + class TestAddUserToUserYaml { + @Test + void shouldCallAddNewUserToList() { + service.addUserToUserYaml(users, namespace, userPassword); + + verify(service).addNewUserToList(eq(users), eq(namespace), anyString()); + } + + @Test + void shouldCallConstructYamlEntries() { + service.addUserToUserYaml(users, namespace, userPassword); + + verify(service).constructYamlEntries(users); + } + + @Test + void shouldReturnUsersYaml() { + when(service.constructYamlEntries(users)).thenReturn("usersYaml"); + + String result = service.addUserToUserYaml(users, namespace, userPassword); + + assertThat(result).isEqualTo("usersYaml"); + } + + @Nested + class TestAddNewUserToList { + @Test + void shouldCallAddUserToList() { + service.addNewUserToList(users, namespace, "passwordHash"); + + verify(users).addUserToList(namespace, "passwordHash", Constants.USER_ROLE); + + } + } + + @Nested + class TestConstructYamlEntries { + @Test + void shouldCallGetUsersList() { + service.constructYamlEntries(users); + + verify(users).getUsersList(); + + } + + @Test + void shouldHaveResultWithCorrectContentStart() { + String result = service.constructYamlEntries(users); + + assertTrue(result.startsWith("fileFormat: 1\nusers:\n")); + } + + @Test + void shouldHaveResultWithCorrectContent() { + when(users.getUsersList()).thenReturn( + OzgCloudElsterTransferConfigMapUserListFactory.create()); + String expectedYaml = "fileFormat: 1\n" + "users:\n" + + " - { login: \"user1\", rolle: \"USER\", credentials: { passwortHash: \"$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a\" }, gruppe: \"user1\" }\n"; + + String result = service.constructYamlEntries(users); + + assertThat(expectedYaml).isEqualTo(result); + } + + @Nested + class TestGetYamlForUser { + @Test + void shouldReturnExpectedYamlForUser() { + Map<String, Object> userEntry = new HashMap<>(); + userEntry.put("login", "user1"); + userEntry.put("rolle", + "USER"); + userEntry.put("gruppe", "user1"); + Map<String, String> credentials = new HashMap<>(); + credentials.put("passwortHash", + "$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a"); + userEntry.put("credentials", credentials); + String expectedYaml = " - { login: \"user1\", rolle: \"USER\", credentials: { passwortHash: \"$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a\" }, gruppe: \"user1\" }"; + + String result = service.getYamlForUser(userEntry); + + assertThat(expectedYaml).isEqualTo(result); + } + + } + + } + + } + + @Nested + class TestUpdateConfigMap { + @Test + void shouldCallUpdateConfigMapData() { + service.updateConfigMap(configMap, "usersYaml"); + + verify(remoteService).updateConfigMapData(configMap, usersKey, "usersYaml"); + } + } + + @Nested + class TestGetUsersFromConfigMap { + @Test + void shouldReturnEmptyUserList() { + ConfigMap configMap = new ConfigMap(); + configMap.setData(new HashMap<>()); + + OzgCloudElsterTransferConfigMapUserList result = service.getUsersFromConfigMap(configMap); + + assertThat(result.getUsersList()).isEmpty(); + } + + @Test + void shouldReturnEmptyUserListWhenUsersYamlIsEmpty() { + ConfigMap configMap = new ConfigMap(); + Map<String, String> data = new HashMap<>(); + data.put(usersKey, ""); + configMap.setData(data); + + OzgCloudElsterTransferConfigMapUserList result = service.getUsersFromConfigMap(configMap); + + assertNotNull(result); + assertThat(result.getUsersList()).isEmpty(); + } + + void shouldReturnParsedUserListWhenUsersYamlIsValid() { + ConfigMap configMap = OzgCloudElsterTransferConfigMapFactory.create(); + + OzgCloudElsterTransferConfigMapUserList result = service.getUsersFromConfigMap(configMap); + Map<String, Object> user1 = result.getUsersList().get(0); + + assertThat(result.getUsersList()).hasSize(1); + assertThat(user1.get("login")).isEqualTo("admin"); + assertThat(user1.get("role")).isEqualTo("ADMIN"); + assertThat(user1.get("passwordHash")).isEqualTo("$2a$12$cqKZMcwTUe/tju7PIFGhperWdV2Xa9o4fVw5eClbzatRhvxZphE1a"); + assertThat(user1.get("group")).isEqualTo("Administratoren"); + } + + } + + } + + @Nested + class TestRestartDeployment { + + @Test + void shouldCallRestartDeployment() { + service.restartDeployment(configMapNamespace, deploymentName); + + verify(remoteService).restartDeployment(configMapNamespace, deploymentName); + } + + } + + @Nested + class TestCreateOrUpdateSecret { + + @Test + void shouldCallRestartDeployment() { + service.createOrUpdateSecret(namespace, userPassword, secretName); + + verify(remoteService).createOrUpdateSecret(namespace, userPassword, secretName); + } + + } + + } + + @Nested + class TestDelete { + + @BeforeEach + void setUp() { + ReflectionTestUtils.setField(service, "etrNamespace", "elster-transfer"); + } + + @Test + void shouldCallUserExists() { + service.delete(OzgCloudElsterTransferUserTestFactory.create()); + + verify(service).userExists(namespace, configMapNamespace, configMapName); + } + + @Test + void shouldCallDeleteUser() { + when(service.userExists(namespace, configMapNamespace, configMapName)).thenReturn(true); + configMap = OzgCloudElsterTransferConfigMapFactory.create(); + when(remoteService.getConfigMap(anyString(), + anyString())).thenReturn(configMap); + + service.delete(OzgCloudElsterTransferUserTestFactory.create()); + + verify(service).deleteUser(namespace, configMapName); + } + + @Test + void shouldCallRestartDeployment() { + when(service.userExists(namespace, configMapNamespace, configMapName)).thenReturn(true); + configMap = OzgCloudElsterTransferConfigMapFactory.create(); + when(remoteService.getConfigMap(anyString(), + anyString())).thenReturn(configMap); + + service.delete(OzgCloudElsterTransferUserTestFactory.create()); + + verify(service).restartDeployment(configMapNamespace, deploymentName); + } + + @Test + void shouldNotCallRestartDeploymentIfUserNotExists() { + service.delete(OzgCloudElsterTransferUserTestFactory.create()); + + verify(service, never()).restartDeployment(any(), any()); + } + + @Test + void shouldNotCallDeleteUserIfUserNotExists() { + service.delete(OzgCloudElsterTransferUserTestFactory.create()); + + verify(service, never()).deleteUser(any(), any()); + } + + @Nested + class TestUserExists { + + @Test + void shouldCallGetConfigMap() { + service.userExists(namespace, configMapNamespace, configMapName); + + verify(service).getConfigMap(configMapNamespace, configMapName); + } + + @Test + void shouldCallGetUsersFromConfigMap() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + + service.userExists(namespace, configMapNamespace, configMapName); + + verify(service).getUsersFromConfigMap(configMap); + } + + @Test + void shouldNotCallGetUsersFromConfigMap() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(null); + + service.userExists(namespace, configMapNamespace, configMapName); + + verify(service, never()).getUsersFromConfigMap(any()); + } + + @Test + void shouldCallExistsUser() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + when(service.getUsersFromConfigMap(configMap)).thenReturn(users); + + service.userExists(namespace, configMapNamespace, configMapName); + + verify(users, times(2)).existsUser(namespace); + } + + @Test + void shouldNotCallExistsUser() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(null); + + service.userExists(namespace, configMapNamespace, configMapName); + + verify(users, never()).existsUser(any()); + } + + @Test + void shouldReturnFalseWhenConfigMapNotExists() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(null); + + boolean result = service.userExists(namespace, configMapNamespace, configMapName); + + assertThat(result).isFalse(); + } + + @Test + void shouldReturnTrueWhenConfigMapExistsAndUserExists() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + when(service.getUsersFromConfigMap(configMap)).thenReturn(users); + when(users.existsUser(namespace)).thenReturn(true); + + boolean result = service.userExists(namespace, configMapNamespace, configMapName); + + assertThat(result).isTrue(); + } + + @Test + void shouldReturnFalseWhenConfigMapExistsButUserNotExists() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + when(service.getUsersFromConfigMap(configMap)).thenReturn(users); + when(users.existsUser(namespace)).thenReturn(false); + + boolean result = service.userExists(namespace, configMapNamespace, configMapName); + + assertThat(result).isFalse(); + } + + } + + @Nested + class TestDeleteUser { + + @BeforeEach + void setUp() { + configMap = OzgCloudElsterTransferConfigMapFactory.create(); + when(remoteService.getConfigMap(anyString(), + anyString())).thenReturn(configMap); + } + + @Test + void shouldCallGetConfigMap() { + service.deleteUser(namespace, configMapName); + + verify(service).getConfigMap(configMapNamespace, configMapName); + } + + @Test + void shouldCallGetUsersFromConfigMap() { + service.deleteUser(namespace, configMapName); + + verify(service).getUsersFromConfigMap(configMap); + } + + @Test + void shouldCallRemoveDeleted() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + when(service.getUsersFromConfigMap(configMap)).thenReturn(users); + + service.deleteUser(namespace, configMapName); + + verify(users).removeDeleted(namespace); + } + + @Test + void shouldCallConstructYamlEntries() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + when(service.getUsersFromConfigMap(configMap)).thenReturn(users); + + service.deleteUser(namespace, configMapName); + + verify(service).constructYamlEntries(users); + } + + @Test + void shouldCallUpdateConfigMapData() { + when(service.getConfigMap(configMapNamespace, configMapName)).thenReturn(configMap); + when(service.getUsersFromConfigMap(configMap)).thenReturn(users); + when(service.constructYamlEntries(users)).thenReturn("updatedUsersYaml"); + + service.deleteUser(namespace, configMapName); + + verify(remoteService).updateConfigMapData(configMap, usersKey, "updatedUsersYaml"); + } + + } + + } +} \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserSpecTestFactory.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserSpecTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..7d107170aaec4ab0bcf6f10a5d582dee03da6f4b --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserSpecTestFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +public class OzgCloudElsterTransferUserSpecTestFactory { + + public static final boolean KEEP_AFTER_DELETE = false; + + public static OzgCloudElsterTransferUserSpec create() { + return createBuilder().build(); + } + + public static OzgCloudElsterTransferUserSpec.OzgCloudElsterTransferUserSpecBuilder createBuilder() { + return OzgCloudElsterTransferUserSpec.builder() + .keepAfterDelete(KEEP_AFTER_DELETE); + } +} diff --git a/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserTestFactory.java b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..0edc232f885b6ed00702ff3270a37e75faea9434 --- /dev/null +++ b/src/test/java/de/ozgcloud/operator/elstertransfer/user/OzgCloudElsterTransferUserTestFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.operator.elstertransfer.user; + +public class OzgCloudElsterTransferUserTestFactory { + + public static final String METADATA_NAMESPACE = "TestNamespace"; + + public static OzgCloudElsterTransferUser create() { + return createWithSpec(OzgCloudElsterTransferUserSpecTestFactory.create()); + } + + public static OzgCloudElsterTransferUser create(OzgCloudElsterTransferUserSpec spec) { + return createWithSpec(spec); + } + + private static OzgCloudElsterTransferUser createWithSpec(OzgCloudElsterTransferUserSpec spec) { + var user = new OzgCloudElsterTransferUser(); + user.setSpec(spec); + user.setStatus(OzgCloudElsterTransferStatusTestFactory.create()); + user.getMetadata().setNamespace(METADATA_NAMESPACE); + + return user; + } +} diff --git a/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 0000000000000000000000000000000000000000..79b126e6cdb86bec1f4f08c205de8961bde1934a --- /dev/null +++ b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +org.mockito.junit.jupiter.MockitoExtension \ No newline at end of file diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties new file mode 100644 index 0000000000000000000000000000000000000000..b059a65dc46792ea5494de02f888ab2ad08cd420 --- /dev/null +++ b/src/test/resources/junit-platform.properties @@ -0,0 +1 @@ +junit.jupiter.extensions.autodetection.enabled=true \ No newline at end of file diff --git a/src/test/resources/users.yaml b/src/test/resources/users.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7f8941cd240f0ad1a3e65706f3281dc0d7a156e6 --- /dev/null +++ b/src/test/resources/users.yaml @@ -0,0 +1,7 @@ +fileFormat: 1 +users: + - login: "{{login}}" + rolle: "{{role}}" + credentials: + passwortHash: "{{passwordHash}}" + gruppe: "{{group}}"