diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5ed0503fa6a3732a934709dd3481d3cc36cadee9..e8dd8fb7e63a49c30f423a6063283352ca526143 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -658,7 +658,7 @@ smoketest-uc4-hazelcastjet: .theodolite: image: - name: ghcr.io/graalvm/native-image:java11-21.3.0 + name: ghcr.io/graalvm/native-image:ol8-java17-22.3.3 entrypoint: [""] variables: GRADLE_OPTS: "-Dorg.gradle.daemon=false" diff --git a/theodolite/.gitignore b/theodolite/.gitignore index 285b6baee527835a20f0b79f1ecece49b80f7d42..216783d79cafca20c19eca37614f1817765af263 100644 --- a/theodolite/.gitignore +++ b/theodolite/.gitignore @@ -34,3 +34,6 @@ nb-configuration.xml # Local environment .env + +# Plugin directory +/.quarkus/cli/plugins/ diff --git a/theodolite/README.md b/theodolite/README.md index 1d2e0acd52ff6bdfbc30f8d2b291f673f8719356..5bf0a7468a547b0d0de1445af36f432075e258e9 100644 --- a/theodolite/README.md +++ b/theodolite/README.md @@ -2,7 +2,7 @@ This project uses Quarkus, the Supersonic Subatomic Java Framework. -If you want to learn more about Quarkus, please visit its website: https://quarkus.io/. +If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . ## Running the application in dev mode @@ -50,8 +50,7 @@ Or, if you don't have GraalVM installed, you can run the native executable build ./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true ``` -You can then execute your native executable with: -```./build/theodolite-0.10.0-SNAPSHOT-runner``` +You can then execute your native executable with: `./build/theodolite-0.10.0-SNAPSHOT-runner` If you want to learn more about building native executables, please consult https://quarkus.io/guides/gradle-tooling. diff --git a/theodolite/build.gradle b/theodolite/build.gradle index 9a997242adf12eb3e5aa30549088d52cf305ef19..c01f261c7bd3c9e9b62bc7efeb93c492c499ab07 100644 --- a/theodolite/build.gradle +++ b/theodolite/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version "1.6.10" - id "org.jetbrains.kotlin.plugin.allopen" version "1.6.10" + id 'org.jetbrains.kotlin.jvm' version "1.8.22" + id "org.jetbrains.kotlin.plugin.allopen" version "1.8.22" id 'io.quarkus' id "io.gitlab.arturbosch.detekt" version "1.15.0" id "org.jlleitschuh.gradle.ktlint" version "10.0.0" @@ -12,11 +12,15 @@ repositories { } dependencies { - implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}") + // Use latest Kubernetes client to use TestStandardHttpClient for exec commands tests + implementation platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}") + implementation enforcedPlatform("io.fabric8:kubernetes-client-bom:6.8.0") + // Use default Quarkus once kubernetes-client 6.8.* is integrated + //implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}") implementation 'io.quarkus:quarkus-kotlin' implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' implementation 'io.quarkus:quarkus-arc' - implementation 'io.quarkus:quarkus-resteasy' + //implementation 'io.quarkus:quarkus-resteasy' implementation 'io.quarkus:quarkus-kubernetes-client' implementation 'org.bouncycastle:bcprov-ext-jdk15on:1.69' @@ -29,6 +33,12 @@ dependencies { testImplementation 'io.quarkus:quarkus-junit5' testImplementation 'io.quarkus:quarkus-test-kubernetes-client' + // Used for exec command tests + testImplementation ('io.fabric8:kubernetes-client-api') { + artifact { + classifier = 'tests' + } + } //testImplementation 'io.rest-assured:rest-assured' testImplementation 'com.github.tomakehurst:wiremock-jre8:2.35.0' testImplementation 'org.junit-pioneer:junit-pioneer:2.0.1' @@ -39,29 +49,31 @@ group 'theodolite' version '0.10.0-SNAPSHOT' java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } allOpen { - annotation("javax.ws.rs.Path") - annotation("javax.enterprise.context.ApplicationScoped") + annotation("jakarta.ws.rs.Path") + annotation("jakarta.enterprise.context.ApplicationScoped") annotation("io.quarkus.test.junit.QuarkusTest") } compileKotlin { - kotlinOptions.jvmTarget = JavaVersion.VERSION_11 + kotlinOptions.jvmTarget = JavaVersion.VERSION_17 kotlinOptions.javaParameters = true } compileTestKotlin { - kotlinOptions.jvmTarget = JavaVersion.VERSION_11 + kotlinOptions.jvmTarget = JavaVersion.VERSION_17 } test { + // systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager" + // Required because of https://github.com/quarkusio/quarkus/issues/18973 - minHeapSize = "256m" - maxHeapSize = "1024m" + minHeapSize = "512m" + maxHeapSize = "2048m" // Temporary fix environment variable test jvmArgs = [ diff --git a/theodolite/gradle.properties b/theodolite/gradle.properties index a7c5a39013639072e1ef47f9226b95b513d678d7..008ce78ac0ab357e1d6d2663be608420d5580585 100644 --- a/theodolite/gradle.properties +++ b/theodolite/gradle.properties @@ -1,8 +1,6 @@ #Gradle properties quarkusPluginId=io.quarkus -quarkusPluginVersion=2.7.4.Final +quarkusPluginVersion=3.2.2.Final quarkusPlatformGroupId=io.quarkus.platform quarkusPlatformArtifactId=quarkus-bom -quarkusPlatformVersion=2.7.4.Final - -#org.gradle.logging.level=INFO \ No newline at end of file +quarkusPlatformVersion=3.2.2.Final diff --git a/theodolite/settings.gradle b/theodolite/settings.gradle index a726b4afa4cfdc7433dbd408808ab0fd6a766d6a..bfa19d83d8ae401b27b659cf97c1126d850d2154 100644 --- a/theodolite/settings.gradle +++ b/theodolite/settings.gradle @@ -1,8 +1,8 @@ pluginManagement { repositories { - mavenLocal() mavenCentral() gradlePluginPortal() + mavenLocal() } plugins { id "${quarkusPluginId}" version "${quarkusPluginVersion}" diff --git a/theodolite/src/main/docker/Dockerfile.jvm b/theodolite/src/main/docker/Dockerfile.jvm index e33d7c379a4336610c16d59b9d3315a1e8abad2b..3e95ceb48000a129f250477d4db37f4ad6272f0a 100644 --- a/theodolite/src/main/docker/Dockerfile.jvm +++ b/theodolite/src/main/docker/Dockerfile.jvm @@ -14,19 +14,73 @@ # docker run -i --rm -p 8080:8080 quarkus/theodolite-jvm # # If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 +# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. +# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 +# when running the container # # Then run the container using : # # docker run -i --rm -p 8080:8080 quarkus/theodolite-jvm # +# This image uses the `run-java.sh` script to run the application. +# This scripts computes the command line to execute your Java application, and +# includes memory/GC tuning. +# You can configure the behavior using the following environment properties: +# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") +# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options +# in JAVA_OPTS (example: "-Dsome.property=foo") +# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is +# used to calculate a default maximal heap memory based on a containers restriction. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio +# of the container available memory as set here. The default is `50` which means 50% +# of the available memory is used as an upper boundary. You can skip this mechanism by +# setting this value to `0` in which case no `-Xmx` option is added. +# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This +# is used to calculate a default initial heap memory based on the maximum heap memory. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio +# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` +# is used as the initial heap size. You can skip this mechanism by setting this value +# to `0` in which case no `-Xms` option is added (example: "25") +# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. +# This is used to calculate the maximum value of the initial heap memory. If used in +# a container without any memory constraints for the container then this option has +# no effect. If there is a memory constraint then `-Xms` is limited to the value set +# here. The default is 4096MB which means the calculated value of `-Xms` never will +# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") +# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output +# when things are happening. This option, if set to true, will set +# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). +# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: +# true"). +# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). +# - CONTAINER_CORE_LIMIT: A calculated core limit as described in +# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") +# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). +# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. +# (example: "20") +# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. +# (example: "40") +# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. +# (example: "4") +# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus +# previous GC times. (example: "90") +# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") +# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") +# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should +# contain the necessary JRE command-line options to specify the required GC, which +# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). +# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") +# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") +# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be +# accessed directly. (example: "foo.example.com,bar.example.com") +# ### -FROM registry.access.redhat.com/ubi8/openjdk-11-runtime:1.10 +FROM registry.access.redhat.com/ubi8/openjdk-17:1.16 -ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' +ENV LANGUAGE='en_US:en' -# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. -ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" # We make four distinct layers so if there are application changes the library layers can be re-used COPY --chown=185 build/quarkus-app/lib/ /deployments/lib/ @@ -36,6 +90,8 @@ COPY --chown=185 build/quarkus-app/quarkus/ /deployments/quarkus/ EXPOSE 8080 USER 185 +ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" -ENTRYPOINT [ "java", "-jar", "/deployments/quarkus-run.jar" ] +ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] diff --git a/theodolite/src/main/docker/Dockerfile.legacy-jar b/theodolite/src/main/docker/Dockerfile.legacy-jar index aa5908c4ed42f005fa67c17fd2c3b3e00978228a..97d0b53b23d8252f62148060100df0c28c9a7739 100644 --- a/theodolite/src/main/docker/Dockerfile.legacy-jar +++ b/theodolite/src/main/docker/Dockerfile.legacy-jar @@ -14,24 +14,80 @@ # docker run -i --rm -p 8080:8080 quarkus/theodolite-legacy-jar # # If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 +# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. +# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 +# when running the container # # Then run the container using : # # docker run -i --rm -p 8080:8080 quarkus/theodolite-legacy-jar # +# This image uses the `run-java.sh` script to run the application. +# This scripts computes the command line to execute your Java application, and +# includes memory/GC tuning. +# You can configure the behavior using the following environment properties: +# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") +# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options +# in JAVA_OPTS (example: "-Dsome.property=foo") +# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is +# used to calculate a default maximal heap memory based on a containers restriction. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio +# of the container available memory as set here. The default is `50` which means 50% +# of the available memory is used as an upper boundary. You can skip this mechanism by +# setting this value to `0` in which case no `-Xmx` option is added. +# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This +# is used to calculate a default initial heap memory based on the maximum heap memory. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio +# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` +# is used as the initial heap size. You can skip this mechanism by setting this value +# to `0` in which case no `-Xms` option is added (example: "25") +# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. +# This is used to calculate the maximum value of the initial heap memory. If used in +# a container without any memory constraints for the container then this option has +# no effect. If there is a memory constraint then `-Xms` is limited to the value set +# here. The default is 4096MB which means the calculated value of `-Xms` never will +# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") +# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output +# when things are happening. This option, if set to true, will set +# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). +# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: +# true"). +# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). +# - CONTAINER_CORE_LIMIT: A calculated core limit as described in +# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") +# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). +# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. +# (example: "20") +# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. +# (example: "40") +# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. +# (example: "4") +# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus +# previous GC times. (example: "90") +# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") +# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") +# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should +# contain the necessary JRE command-line options to specify the required GC, which +# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). +# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") +# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") +# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be +# accessed directly. (example: "foo.example.com,bar.example.com") +# ### -FROM registry.access.redhat.com/ubi8/openjdk-11-runtime:1.10 +FROM registry.access.redhat.com/ubi8/openjdk-17:1.16 -ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' +ENV LANGUAGE='en_US:en' -# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. -ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" COPY build/lib/* /deployments/lib/ COPY build/*-runner.jar /deployments/quarkus-run.jar EXPOSE 8080 USER 185 +ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" -ENTRYPOINT [ "java", "-jar", "/deployments/quarkus-run.jar" ] +ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] diff --git a/theodolite/src/main/docker/Dockerfile.native b/theodolite/src/main/docker/Dockerfile.native index 34ccd6622bf2fba6f9707989fffd9bb6390a4a8b..a81683b0436b2dbe85fae64f9e7031626f1568e9 100644 --- a/theodolite/src/main/docker/Dockerfile.native +++ b/theodolite/src/main/docker/Dockerfile.native @@ -1,5 +1,5 @@ #### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode +# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. # # Before building the container image run: # @@ -14,7 +14,7 @@ # docker run -i --rm -p 8080:8080 quarkus/theodolite # ### -FROM quay.io/quarkus/quarkus-micro-image:1.0 +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8 WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ @@ -24,4 +24,4 @@ COPY --chown=1001:root build/*-runner /work/application EXPOSE 8080 USER 1001 -CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] +ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/theodolite/src/main/docker/Dockerfile.native-micro b/theodolite/src/main/docker/Dockerfile.native-micro new file mode 100644 index 0000000000000000000000000000000000000000..ea4cf374ffc199525308113f38f3e74cc5d864cb --- /dev/null +++ b/theodolite/src/main/docker/Dockerfile.native-micro @@ -0,0 +1,30 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. +# It uses a micro base image, tuned for Quarkus native executables. +# It reduces the size of the resulting container image. +# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image. +# +# Before building the container image run: +# +# ./gradlew build -Dquarkus.package.type=native +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/theodolite . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/theodolite +# +### +FROM quay.io/quarkus/quarkus-micro-image:2.0 +WORKDIR /work/ +RUN chown 1001 /work \ + && chmod "g+rwX" /work \ + && chown 1001:root /work +COPY --chown=1001:root build/*-runner /work/application + +EXPOSE 8080 +USER 1001 + +ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Action.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Action.kt index bdabb719672abf2975fdf8a0ad59868bbc6c1edf..486bbb88903b9222ea4864fdfaf115d55de12851 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Action.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Action.kt @@ -3,6 +3,7 @@ package rocks.theodolite.kubernetes import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import io.fabric8.kubernetes.client.KubernetesClient import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.quarkus.runtime.annotations.RegisterForReflection @@ -18,11 +19,11 @@ class Action { @JsonInclude(JsonInclude.Include.NON_NULL) var deleteCommand: DeleteCommand? = null - fun exec(client: NamespacedKubernetesClient) { + fun exec(client: KubernetesClient) { return if (execCommand != null) { - execCommand?.exec(client= client) !! + execCommand?.exec(client) !! } else if (deleteCommand != null) { - deleteCommand?.exec(client= client ) !! + deleteCommand?.exec(client) !! } else { throw DeploymentFailedException("Could not execute action. The action type must either be 'exec' or 'delete'.") } diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ActionCommand.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ActionCommand.kt index eefacbea9268f44969fd88d7650d5ddc5e00fb8e..e6dac50627652731fc7c00d127283b052d043a52 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ActionCommand.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ActionCommand.kt @@ -1,33 +1,26 @@ package rocks.theodolite.kubernetes -import io.fabric8.kubernetes.api.model.Status +import io.fabric8.kubernetes.client.KubernetesClient import io.fabric8.kubernetes.client.KubernetesClientException -import io.fabric8.kubernetes.client.NamespacedKubernetesClient -import io.fabric8.kubernetes.client.dsl.ExecListener import io.fabric8.kubernetes.client.dsl.ExecWatch -import io.fabric8.kubernetes.client.utils.Serialization import mu.KotlinLogging import java.io.ByteArrayOutputStream import java.time.Duration -import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit private val logger = KotlinLogging.logger {} -class ActionCommand(val client: NamespacedKubernetesClient) { - var out: ByteArrayOutputStream = ByteArrayOutputStream() - var error: ByteArrayOutputStream = ByteArrayOutputStream() - var errChannelStream: ByteArrayOutputStream = ByteArrayOutputStream() - private val execLatch = CountDownLatch(1) +class ActionCommand(val client: KubernetesClient) { /** * Executes an action command. * * @param matchLabels matchLabels specifies on which pod the command should be executed. For this, the principle * `of any` of is used and the command is called on one of the possible pods. - * @param container (Optional) The container to run the command. Is optional iff exactly one container exist. * @param command The command to be executed. + * @param timeout (Optional) Timeout for running the command. + * @param container (Optional) The container to run the command. Is optional iff exactly one container exist. * @return the exit code of this executed command */ fun exec( @@ -37,69 +30,26 @@ class ActionCommand(val client: NamespacedKubernetesClient) { container: String = "" ): Int { try { - val execWatch: ExecWatch = if (container.isNotEmpty()) { - client.pods() - .inNamespace(client.namespace) - .withName(getPodName(matchLabels, 3)) - .inContainer(container) - - } else { - client.pods() - .inNamespace(client.namespace) - .withName(getPodName(matchLabels, 3)) - } - .writingOutput(out) - .writingError(error) - .writingErrorChannel(errChannelStream) - .usingListener(ActionCommandListener(execLatch)) + val outStream = ByteArrayOutputStream() + val errorStream = ByteArrayOutputStream() + val execWatch: ExecWatch = client.pods() + .inNamespace(client.namespace) + .withName(awaitPodName(matchLabels, 3)) + .let { if (container.isNotEmpty()) it.inContainer(container) else it } + .writingOutput(outStream) + .writingError(errorStream) .exec(*command) - - val latchTerminationStatus = execLatch.await(timeout, TimeUnit.SECONDS) - if (!latchTerminationStatus) { - throw ActionCommandFailedException("Timeout while running action command") - } + val exitCode = execWatch.exitCode().get(timeout, TimeUnit.SECONDS) execWatch.close() - } catch (e: Exception) { - when (e) { - is InterruptedException -> { - Thread.currentThread().interrupt() - throw ActionCommandFailedException("Interrupted while waiting for the exec", e) - } - is KubernetesClientException -> { - throw ActionCommandFailedException("Error while executing command", e) - } - else -> { - throw e - } - } + logger.debug { "Execution Output Stream is \n $outStream" } + logger.debug { "Execution Error Stream is \n $errorStream" } + return exitCode + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + throw ActionCommandFailedException("Interrupted while waiting for the exec", e) + } catch (e: KubernetesClientException) { + throw ActionCommandFailedException("Error while executing command", e) } - logger.debug { "Execution Output Stream is \n $out" } - logger.debug { "Execution Error Stream is \n $error" } - logger.debug { "Execution ErrorChannel is: \n $errChannelStream" } - return getExitCode(errChannelStream) - } - - private fun getExitCode(errChannelStream: ByteArrayOutputStream): Int { - val status: Status? - try { - status = Serialization.unmarshal(errChannelStream.toString(), Status::class.java) - } catch (e: Exception) { - throw ActionCommandFailedException("Could not determine the exit code, no information given") - } - - if (status == null) { - throw ActionCommandFailedException("Could not determine the exit code, no information given") - } - - return if (status.status.equals("Success")) { - 0 - } else status.details.causes.stream() - .filter { it.reason.equals("ExitCode") } - .map { it.message } - .findFirst() - .orElseThrow { - ActionCommandFailedException("Status is not SUCCESS but contains no exit code - Status: $status") - }.toInt() } /** @@ -110,9 +60,8 @@ class ActionCommand(val client: NamespacedKubernetesClient) { * it can take a while until the status is ready and the pod can be selected. * @return the name of the pod or throws [ActionCommandFailedException] */ - fun getPodName(matchLabels: Map<String, String>, tries: Int): String { + fun awaitPodName(matchLabels: Map<String, String>, tries: Int): String { for (i in 1..tries) { - try { return getPodName(matchLabels) } catch (e: Exception) { @@ -141,16 +90,4 @@ class ActionCommand(val client: NamespacedKubernetesClient) { } } - private class ActionCommandListener(val execLatch: CountDownLatch) : ExecListener { - - override fun onFailure(throwable: Throwable, response: ExecListener.Response) { - execLatch.countDown() - throw ActionCommandFailedException("Some error encountered while executing action, caused ${throwable.message})") - } - - override fun onClose(code: Int, reason: String) { - execLatch.countDown() - } - } - } diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSet.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSet.kt index 43c478b983d879135b00e6208df8bb36b7978c8f..15a2f6d32a54faa51662a4288f8f7cf079c3d77b 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSet.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSet.kt @@ -41,7 +41,7 @@ class ConfigMapResourceSet : ResourceSet, KubernetesResource { .map { Pair( it.key, // filename - client.resource(it.value).get() + client.resource(it.value).item() ) } } catch (e: IllegalArgumentException) { diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/DeleteCommand.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/DeleteCommand.kt index ef4409e5bdebfa8b232d5ed1080e93571cbaa618..502fb9b23558564a62bc2a0093fcfc25ede04823 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/DeleteCommand.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/DeleteCommand.kt @@ -2,8 +2,8 @@ package rocks.theodolite.kubernetes import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import io.fabric8.kubernetes.client.KubernetesClient import io.fabric8.kubernetes.client.KubernetesClientException -import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.quarkus.runtime.annotations.RegisterForReflection import mu.KotlinLogging @@ -16,7 +16,7 @@ class DeleteCommand { lateinit var selector: DeleteActionSelector - fun exec(client: NamespacedKubernetesClient) { + fun exec(client: KubernetesClient) { logger.info { "Deleting all resources with apiVersion ${selector.apiVersion} and Kind ${selector.kind} matching regular expression ${selector.nameRegex}" } val regExp = selector.nameRegex.toRegex() val k8sManager = K8sManager(client) diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExecCommand.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExecCommand.kt index b8ce10efcd3e4fb5ea552aa7f922fd81c5c13656..1691b414695c3eaaa207ff9c70788bf4e7801b71 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExecCommand.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExecCommand.kt @@ -2,7 +2,7 @@ package rocks.theodolite.kubernetes import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import io.fabric8.kubernetes.client.KubernetesClient import io.quarkus.runtime.annotations.RegisterForReflection @JsonDeserialize @@ -12,7 +12,7 @@ class ExecCommand { lateinit var selector: ExecActionSelector lateinit var command: Array<String> var timeoutSeconds: Long = Configuration.TIMEOUT_SECONDS - fun exec(client: NamespacedKubernetesClient) { + fun exec(client: KubernetesClient) { val exitCode = ActionCommand(client = client) .exec( matchLabels = selector.pod.matchLabels, @@ -20,7 +20,7 @@ class ExecCommand { timeout = timeoutSeconds, command = command ) - if (exitCode != 0){ + if (exitCode != 0) { throw ActionCommandFailedException("Error while executing action, finished with exit code $exitCode") } } diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExperimentRunnerImpl.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExperimentRunnerImpl.kt index 3e964a1e0d5a9e512a9eefa16b90acf588a537eb..707ef1b8f8bb81eb3823c78b67d30478a4f7b76c 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExperimentRunnerImpl.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ExperimentRunnerImpl.kt @@ -60,8 +60,7 @@ class ExperimentRunnerImpl( .analyze( load = load, resource = resource, - executionIntervals = executionIntervals, - metric = this.results.metric + executionIntervals = executionIntervals ) } diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSet.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSet.kt index 6f430d54cfe9898324b7b9c33df6646b9e6d06ff..6a0b0203f1fcc0f349d495d7c58392c2c9479821 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSet.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSet.kt @@ -45,7 +45,7 @@ class FileSystemResourceSet: ResourceSet, KubernetesResource { val text = BufferedReader(InputStreamReader(it, StandardCharsets.UTF_8)) .lines() .collect(Collectors.joining("\n")) - val k8sResource = client.resource(text).get() + val k8sResource = client.resource(text).item() Pair(resource.last().toString(), k8sResource) } } catch (e: FileNotFoundException){ diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/K8sManager.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/K8sManager.kt index 7856451edf4c31d668288f618fcee46b7246a619..0b34f4564829307df27f6910c5a7753f362b3dcf 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/K8sManager.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/K8sManager.kt @@ -3,6 +3,7 @@ package rocks.theodolite.kubernetes import io.fabric8.kubernetes.api.model.HasMetadata import io.fabric8.kubernetes.api.model.apps.Deployment import io.fabric8.kubernetes.api.model.apps.StatefulSet +import io.fabric8.kubernetes.client.KubernetesClient import io.fabric8.kubernetes.client.NamespacedKubernetesClient import mu.KotlinLogging @@ -13,7 +14,7 @@ private val logger = KotlinLogging.logger {} * Supports: Deployments, Services, ConfigMaps, StatefulSets, and CustomResources. * @param client KubernetesClient used to deploy or remove. */ -class K8sManager(private val client: NamespacedKubernetesClient) { +class K8sManager(private val client: KubernetesClient) { /** * Deploys different k8s resources using the client. diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ResourceByLabelHandler.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ResourceByLabelHandler.kt index 6fdf80e3c1fcace633adc135123fb95ab49d1fc4..ab42a67dd795c3fbd7469d590d6e547647088daa 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ResourceByLabelHandler.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/ResourceByLabelHandler.kt @@ -1,5 +1,6 @@ package rocks.theodolite.kubernetes +import io.fabric8.kubernetes.client.KubernetesClient import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext import mu.KotlinLogging @@ -10,7 +11,7 @@ private val logger = KotlinLogging.logger {} * The ResourceByLabelHandler provides basic functions to manage Kubernetes resources through their labels. * @param client NamespacedKubernetesClient used for the deletion. */ -class ResourceByLabelHandler(private val client: NamespacedKubernetesClient) { +class ResourceByLabelHandler(private val client: KubernetesClient) { /** * Deletes all pods with the selected label. diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/AbstractStateHandler.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/AbstractStateHandler.kt index 96593914cf07c427c924a1631a00f76dc3649ed3..775669bec3f682661416106731dc2563c2ba6595 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/AbstractStateHandler.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/AbstractStateHandler.kt @@ -38,12 +38,8 @@ abstract class AbstractStateHandler<S : HasMetadata>( } @Synchronized - fun getState(resourceName: String, f: (S) -> String?): String? { - return this.crdClient - .list().items - .filter { it.metadata.name == resourceName } - .map { customResource -> f(customResource) } - .firstOrNull() + fun getState(resourceName: String, stateAccessor: (S) -> String?): String? { + return this.crdClient.withName(resourceName)?.get()?.let(stateAccessor) } @Synchronized diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateHandler.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateHandler.kt index 9a272b43f911bf523adf7c64c5ab34793b7a7dc5..834a8ddaaafbfd7376dd8f8ecac75ab9332d11c3 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateHandler.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateHandler.kt @@ -3,6 +3,7 @@ package rocks.theodolite.kubernetes.operator import io.fabric8.kubernetes.client.NamespacedKubernetesClient import rocks.theodolite.kubernetes.model.crd.BenchmarkCRD import rocks.theodolite.kubernetes.model.crd.BenchmarkState +import rocks.theodolite.kubernetes.model.crd.ExecutionCRD import rocks.theodolite.kubernetes.model.crd.ExecutionState class BenchmarkStateHandler(val client: NamespacedKubernetesClient) : @@ -11,15 +12,15 @@ class BenchmarkStateHandler(val client: NamespacedKubernetesClient) : crd = BenchmarkCRD::class.java ) { - private fun getBenchmarkResourceState() = { cr: BenchmarkCRD -> cr.status.resourceSetsState.value } + private val benchmarkResourceStateAccessor = { cr: BenchmarkCRD -> cr.status.resourceSetsState.value } fun setResourceSetState(resourceName: String, status: BenchmarkState): Boolean { setState(resourceName) { cr -> cr.status.resourceSetsState = status; cr } - return blockUntilStateIsSet(resourceName, status.value, getBenchmarkResourceState()) + return blockUntilStateIsSet(resourceName, status.value, benchmarkResourceStateAccessor) } fun getResourceSetState(resourceName: String): ExecutionState { - val status = this.getState(resourceName, getBenchmarkResourceState()) + val status = this.getState(resourceName, benchmarkResourceStateAccessor) return if (status.isNullOrBlank()) { ExecutionState.NO_STATE } else { diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ExecutionStateHandler.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ExecutionStateHandler.kt index cb3dca8a6389e0db4c064e0d65929daab5cebc90..2ef38a1d74c358b1c9ffa44d2d574aedf91a62e0 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ExecutionStateHandler.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ExecutionStateHandler.kt @@ -16,15 +16,15 @@ class ExecutionStateHandler(val client: NamespacedKubernetesClient) : private var runExecutionDurationTimer: AtomicBoolean = AtomicBoolean(false) - private fun getExecutionLambda() = { cr: ExecutionCRD -> cr.status.executionState.value } + private val executionStateAccessor = { cr: ExecutionCRD -> cr.status.executionState.value } fun setExecutionState(resourceName: String, status: ExecutionState): Boolean { super.setState(resourceName) { cr -> cr.status.executionState = status; cr } - return blockUntilStateIsSet(resourceName, status.value, getExecutionLambda()) + return blockUntilStateIsSet(resourceName, status.value, executionStateAccessor) } fun getExecutionState(resourceName: String): ExecutionState { - val statusString = this.getState(resourceName, getExecutionLambda()) + val statusString = this.getState(resourceName, executionStateAccessor) return ExecutionState.values().first { it.value == statusString } } diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt index e4677018563a078fc2ec796ed71d4b886a6dea00..ecc0cc3f769c74ff29b852842210c192b525e86b 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt @@ -45,17 +45,6 @@ class TheodoliteOperator(private val client: NamespacedKubernetesClient) { private fun startOperator() { logger.info { "Becoming the leading operator. Use namespace '${this.client.namespace}'." } client.use { - KubernetesDeserializer.registerCustomKind( - "$GROUP/$API_VERSION", - EXECUTION_SINGULAR, - ExecutionCRD::class.java - ) - - KubernetesDeserializer.registerCustomKind( - "$GROUP/$API_VERSION", - BENCHMARK_SINGULAR, - BenchmarkCRD::class.java - ) ClusterSetup( executionCRDClient = getExecutionClient(), diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt index 28b2d55d49206df935b4a5303b045e2a69bbd1ac..d51ce7299b703c7258d450170c8b59d351750498 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt @@ -27,7 +27,7 @@ class ConfigMapYamlPatcher( val parser = Yaml(dumperOptions) // Change value - val yaml = parser.loadAs(yamlFile, LinkedHashMap<String, Any>()::class.java) + val yaml: MutableMap<String, Any> = parser.loadAs(yamlFile, LinkedHashMap<String, Any>()::class.java) yaml[variableName] = value.toLongOrNull() ?: value.toDoubleOrNull() ?: value.toBooleanStrictOrNull() ?: value // Convert back to String and set in Kubernetes resource diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcher.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcher.kt index d74c8a22d0b0f06d5f80c299decdb1f0160cd5b2..097c8a03d25a6c7763c730f39fb28f41e469eb6a 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcher.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcher.kt @@ -22,7 +22,7 @@ class GenericResourcePatcher(val path: List<Any>, val type: Type = Type.STRING) var current: Any? = resource.additionalProperties for (segment in path.dropLast(1)) { current = if (segment is Int && current is MutableList<*> && current.size > segment) { - current.toTypedArray()[segment] + current[segment] } else if (segment is String && current is Map<*, *>) { current[segment] } else { @@ -33,8 +33,10 @@ class GenericResourcePatcher(val path: List<Any>, val type: Type = Type.STRING) if (segment == null) { throw IllegalArgumentException("Path must not be empty") } else if (segment is Int && current is MutableList<*> && current.size > segment) { + @Suppress("UNCHECKED_CAST") (current as MutableList<Any?>)[segment] = castedValue } else if (segment is String && current is Map<*, *>) { + @Suppress("UNCHECKED_CAST") (current as MutableMap<String, Any>)[segment] = castedValue } else { throw IllegalArgumentException("Cannot set value for path") diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/AnalysisExecutor.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/AnalysisExecutor.kt index b7cd32d735fe2cdc0888df4a563499ca76b60886..a4a775bad2a551a55dbe4e442aee395ad96c337b 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/AnalysisExecutor.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/AnalysisExecutor.kt @@ -31,7 +31,7 @@ class AnalysisExecutor( * @param executionIntervals list of start and end points of experiments * @return true if the experiment succeeded. */ - fun analyze(load: Int, resource: Int, executionIntervals: List<Pair<Instant, Instant>>, metric: Metric): Boolean { + fun analyze(load: Int, resource: Int, executionIntervals: List<Pair<Instant, Instant>>): Boolean { var repetitionCounter = 1 try { @@ -60,8 +60,7 @@ class AnalysisExecutor( sloType = slo.sloType, properties = slo.properties, load = load, - resources = resource, - metric = metric + resources = resource ) return sloChecker.evaluate(prometheusData) diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactory.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactory.kt index 2c4caea44cd0d6b9534c2ed69f1db5df721408ad..32aa2f5cf298121be2c1e2791ae4cf6ad50fa73d 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactory.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactory.kt @@ -45,8 +45,7 @@ class SloCheckerFactory { sloType: String, properties: Map<String, String>, load: Int, - resources: Int, - metric: Metric + resources: Int ): SloChecker = when (SloTypes.from(sloType)) { SloTypes.GENERIC -> ExternalSloChecker( diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloConfigHandler.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloConfigHandler.kt index 404255496f57f7e25259268db6d04a8c81139f75..7a24bfca3a992d98451ab19d17d9ee246b2afa5a 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloConfigHandler.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/slo/SloConfigHandler.kt @@ -2,7 +2,7 @@ package rocks.theodolite.kubernetes.slo import rocks.theodolite.kubernetes.model.KubernetesBenchmark.Slo import rocks.theodolite.kubernetes.patcher.InvalidPatcherConfigurationException -import javax.enterprise.context.ApplicationScoped +import jakarta.enterprise.context.ApplicationScoped private const val DEFAULT_CONSUMER_LAG_METRIC_BASE = "kafka_consumergroup_lag" private const val DEFAULT_CONSUMER_LAG_QUERY = "sum by(consumergroup) (kafka_consumergroup_lag >= 0)" diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/Parser.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/Parser.kt index 65cd6a39303d3f0f0814c7197bbe15b4919be5d7..53c4ac20cb6d7d002423683847f49b7e303d4b28 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/Parser.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/Parser.kt @@ -9,8 +9,8 @@ interface Parser { * Parse a file. * * @param path The path of the file - * @param E The class of the type to parse + * @param clazz The class of the type to parse * @param T The type to parse */ - fun <T> parse(path: String, E: Class<T>): T? + fun <T> parse(path: String, clazz: Class<T>): T? } diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/YamlParserFromFile.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/YamlParserFromFile.kt index fb5b1e419aa2f6fcc369cf14e5104f7efde48d3d..125ac1def3f0635eee0b2c1a6709009a6e5006ea 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/YamlParserFromFile.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/util/YamlParserFromFile.kt @@ -1,5 +1,6 @@ package rocks.theodolite.kubernetes.util +import org.yaml.snakeyaml.LoaderOptions import org.yaml.snakeyaml.Yaml import org.yaml.snakeyaml.constructor.Constructor import java.io.File @@ -13,7 +14,7 @@ import java.io.InputStream class YamlParserFromFile : Parser { override fun <T> parse(path: String, clazz: Class<T>): T? { val input: InputStream = FileInputStream(File(path)) - val parser = Yaml(Constructor(clazz)) + val parser = Yaml(Constructor(clazz, LoaderOptions())) return parser.loadAs(input, clazz) } } diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ActionCommandTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ActionCommandTest.kt index 008bc302f1ba9a246b7bd898aec712f305c5b288..6e7a5407a7113d2d88cf4fab4978f1d92c081aec 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ActionCommandTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ActionCommandTest.kt @@ -1,127 +1,139 @@ package rocks.theodolite.kubernetes -import io.fabric8.kubernetes.api.model.Pod -import io.fabric8.kubernetes.api.model.PodBuilder -import io.fabric8.kubernetes.api.model.PodListBuilder -import io.fabric8.kubernetes.client.server.mock.KubernetesServer -import io.fabric8.kubernetes.client.utils.Utils +import io.fabric8.kubernetes.api.model.* +import io.fabric8.kubernetes.client.ConfigBuilder +import io.fabric8.kubernetes.client.KubernetesClient +import io.fabric8.kubernetes.client.KubernetesClientBuilder +import io.fabric8.kubernetes.client.http.* +import io.fabric8.kubernetes.client.utils.Serialization import io.quarkus.test.junit.QuarkusTest import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals -import rocks.theodolite.kubernetes.operator.TheodoliteController -import rocks.theodolite.kubernetes.operator.TheodoliteOperator +import org.junit.jupiter.api.Assertions.assertTrue +import org.mockito.ArgumentMatchers +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import java.nio.ByteBuffer +import java.nio.charset.StandardCharsets +import java.util.concurrent.CompletableFuture @QuarkusTest class ActionCommandTest { - private val server = KubernetesServer(false, false) - lateinit var controller: TheodoliteController + + private lateinit var factory: TestStandardHttpClientFactory + private lateinit var client: KubernetesClient + private lateinit var httpClient: TestStandardHttpClient @BeforeEach fun setUp() { - server.before() - val operator = TheodoliteOperator(server.client) - this.controller = operator.getController( - executionStateHandler = operator.getExecutionStateHandler(), - benchmarkStateChecker = operator.getBenchmarkStateChecker() - ) - - val pod: Pod = PodBuilder().withNewMetadata() - .withName("pod1") - .withResourceVersion("1") - .withLabels<String, String>(mapOf("app" to "pod")) - .withNamespace("test").and() - .build() - - val ready: Pod = createReadyFrom(pod, "True") - - val podList = PodListBuilder().build() - podList.items.add(0, ready) - - server - .expect() - .withPath("/api/v1/namespaces/test/pods?labelSelector=${Utils.toUrlEncoded("app=pod")}") - .andReturn(200, podList) - .always() - - server - .expect() - .get() - .withPath("/api/v1/namespaces/test/pods/pod1") - .andReturn(200, ready) - .always() - - server - .expect() - .withPath("/api/v1/namespaces/test/pods/pod1/exec?command=ls&stdout=true&stderr=true") - .andUpgradeToWebSocket() - .open(ErrorChannelMessage("{\"metadata\":{},\"status\":\"Success\"}\n")) - .done() - .always() - - server - .expect() - .withPath("/api/v1/namespaces/test/pods/pod1/exec?command=error-command&stdout=true&stderr=true") - .andUpgradeToWebSocket() - .open(ErrorChannelMessage("{\"metadata\":{},\"status\":\"failed\", \"details\":{}}\n")) - .done() - .always() + factory = TestStandardHttpClientFactory() + client = KubernetesClientBuilder() + .withHttpClientFactory(factory) + .withConfig(ConfigBuilder() + .withNamespace("test") + .build()) + .build() + httpClient = factory.instances.iterator().next() + + val podReadyList = PodListBuilder() + .withNewMetadata().endMetadata() + .addNewItem() + .withNewMetadata() + .withName("single-container") + .withLabels<String, String>(mapOf("app" to "single-container")) + .endMetadata() + .withNewSpec().addNewContainer().withName("single-container").endContainer().endSpec() + .withNewStatus().addNewCondition().withType("Ready").withStatus("True").endCondition().endStatus() + .endItem() + .build() + httpClient.expect("/api/v1/namespaces/test/pods", 200, client.kubernetesSerialization.asJson(podReadyList)) + httpClient.expect("/api/v1/namespaces/test/pods/single-container", 200, client.kubernetesSerialization.asJson(podReadyList.items[0])) + // "/api/v1/namespaces/test/pods" will be called twice + httpClient.expect("/api/v1/namespaces/test/pods", 200, client.kubernetesSerialization.asJson(podReadyList)) } - /** - * Copied from fabric8 Kubernetes Client repository - * - * @param pod - * @param status - * @return - */ - fun createReadyFrom(pod: Pod, status: String): Pod { - return PodBuilder(pod) - .withNewStatus() - .addNewCondition() - .withType("Ready") - .withStatus(status) - .endCondition() - .endStatus() - .build() - } @AfterEach fun tearDown() { - server.after() } @Test fun testGetPodName() { - assertEquals("pod1", ActionCommand(client = server.client).getPodName(mutableMapOf("app" to "pod"), 1)) + assertEquals("single-container", ActionCommand(client = client).awaitPodName(mapOf("app" to "single-container"), 1)) } @Test fun testActionSuccess() { - val action = Action() - action.execCommand = ExecCommand() - action.execCommand!!.selector = ExecActionSelector() - action.execCommand!!.selector.pod = PodSelector() - action.execCommand!!.selector.pod.matchLabels = mutableMapOf("app" to "pod") - action.execCommand!!.command = arrayOf("ls") - action.execCommand!!.timeoutSeconds = 10L - - action.exec(server.client) - assertEquals( - "/api/v1/namespaces/test/pods/pod1/exec?command=ls&stdout=true&stderr=true", - server.lastRequest.path) + val success = StatusBuilder() + .withStatus("Success") + .build() + httpClient.wsExpect("/api/v1/namespaces/test/pods/single-container/exec", buildWsFutureProvider(success)) + + val action = Action().apply { + execCommand = ExecCommand().apply { + selector = ExecActionSelector().apply { + pod = PodSelector().apply { + matchLabels = mapOf("app" to "single-container") + } + } + command = arrayOf("ls") + timeoutSeconds = 10L + } + } + action.exec(this.client) + + val calledUri = httpClient.recordedBuildWebSocketDirects[0].standardWebSocketBuilder.asHttpRequest().uri() + assertTrue(calledUri.toString().contains("/api/v1/namespaces/test/pods/single-container/exec")) + assertTrue(calledUri.toString().contains("command=ls")) } @Test fun testActionFailed() { - val action = Action() - action.execCommand = ExecCommand() - action.execCommand!!.selector = ExecActionSelector() - action.execCommand!!.selector.pod = PodSelector() - action.execCommand!!.selector.pod.matchLabels = mapOf("app" to "pod") - action.execCommand!!.command = arrayOf("error-command") - action.execCommand!!.timeoutSeconds = 10L - - assertThrows<ActionCommandFailedException> { run { action.exec(server.client) } } + val failed = StatusBuilder() + .withStatus("failed") + .withNewDetails() + .endDetails() + .build() + httpClient.wsExpect("/api/v1/namespaces/test/pods/single-container/exec", buildWsFutureProvider(failed)) + + val action = Action().apply { + execCommand = ExecCommand().apply { + selector = ExecActionSelector().apply { + pod = PodSelector().apply { + matchLabels = mapOf("app" to "pod") + } + } + command = arrayOf("exit", "1") + timeoutSeconds = 10L + } + } + + assertThrows<ActionCommandFailedException> { action.exec(this.client) } + + val calledUri = httpClient.recordedBuildWebSocketDirects[0].standardWebSocketBuilder.asHttpRequest().uri() + assertTrue(calledUri.toString().contains("/api/v1/namespaces/test/pods/single-container/exec")) + assertTrue(calledUri.toString().contains("command=exit")) + assertTrue(calledUri.toString().contains("command=1")) + } + + private fun buildBodyBytes(prefix: Byte, body: String): ByteBuffer { + val original = body.toByteArray(StandardCharsets.UTF_8) + return ByteBuffer.allocate(original.size + 1).apply { + put(prefix) + put(original) + } + } + + private fun buildWsFutureProvider(status: Status): TestStandardHttpClient.WsFutureProvider { + val webSocket = mock<WebSocket> { + on { send(ArgumentMatchers.any()) } doReturn(true) + } + return TestStandardHttpClient.WsFutureProvider { _, l -> + l.onOpen(webSocket) + val message = buildBodyBytes(3, Serialization.asJson(status)) + l.onMessage(webSocket, message) // exit + CompletableFuture.completedFuture(WebSocketResponse(WebSocketUpgradeResponse(null), webSocket)) + } } } diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSetTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSetTest.kt index 87058706c1a315c98ba098e6c5835f3a57343112..c0bfc158607c28326c99bf7e8ff054db873a0339 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSetTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/ConfigMapResourceSetTest.kt @@ -17,6 +17,7 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import registerResource @@ -145,6 +146,7 @@ internal class ConfigMapResourceSetTest { } @Test + @Disabled("There is no reason for a special treatment of Execution resources.") fun testLoadExecution() { val stream = javaClass.getResourceAsStream("/k8s-resource-files/test-execution.yaml") val execution = this.executionClient.load(stream).get() @@ -159,6 +161,7 @@ internal class ConfigMapResourceSetTest { } @Test + @Disabled("There is no reason for a special treatment of Benchmark resources.") fun testLoadBenchmark() { val benchmark = BenchmarkCRDummy("example-benchmark").getCR() val createdResource = deployAndGetResource(benchmark).getResourceSet(server.client) @@ -181,7 +184,7 @@ internal class ConfigMapResourceSetTest { server.registerResource(serviceMonitorContext) val stream = javaClass.getResourceAsStream("/k8s-resource-files/test-service-monitor.yaml") - val serviceMonitor = server.client.load(stream).get()[0] + val serviceMonitor = server.client.load(stream).items().first() val createdResource = deployAndGetResource(serviceMonitor).getResourceSet(server.client) assertEquals(1, createdResource.size) diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSetTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSetTest.kt index 1c5f32159713e7ace6857caf0f97b43c90cb36e0..3f10f82e9aff869839e3ef1af9f0721f1b7fe617 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSetTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/FileSystemResourceSetTest.kt @@ -126,6 +126,7 @@ class FileSystemResourceSetTest { } @Test + @Disabled("There is no reason for a special treatment of Benchmark resources.") fun testLoadBenchmark(@TempDir tempDir: Path) { copyTestResourceFile("test-benchmark.yaml", tempDir) @@ -137,6 +138,7 @@ class FileSystemResourceSetTest { } @Test + @Disabled("There is no reason for a special treatment of Execution resources.") fun testLoadExecution(@TempDir tempDir: Path) { copyTestResourceFile("test-execution.yaml", tempDir) diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/K8sManagerTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/K8sManagerTest.kt index 90dd01626a7c18e0b6f8d6018aae54297e758464..fb2d66870fdbc5854acd1d3c7b2051b418f5df29 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/K8sManagerTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/K8sManagerTest.kt @@ -120,7 +120,7 @@ internal class K8sManagerTest { val manager = K8sManager(server.client) val serviceMonitorStream = javaClass.getResourceAsStream("/k8s-resource-files/test-service-monitor.yaml") - val serviceMonitor = server.client.load(serviceMonitorStream).get()[0] + val serviceMonitor = server.client.load(serviceMonitorStream).items().first() manager.deploy(serviceMonitor) diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTest.kt index e794ae1638bd6c7f265b3b7ffb08c2494ba76a37..afbbed1ff077749713fee73589005871d487a808 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTest.kt @@ -107,12 +107,11 @@ class ExecutionEventHandlerTest { val executionResource = getExecutionFromSystemResource("k8s-resource-files/test-execution.yaml") val execution = executionResource.create() val executionName = execution.metadata.name - stateHandler.setExecutionState(executionName, ExecutionState.RUNNING) + //stateHandler.setExecutionState(executionName, ExecutionState.RUNNING) // Update status of execution execution.status.executionState = ExecutionState.RUNNING - executionResource.patchStatus(execution) - + this.executionClient.resource(execution).updateStatus() // Get execution from server val executionResponse = this.executionClient.withName(executionName).get() diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTestWithInformer.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTestWithInformer.kt index 63a669fe67c66b644b6acbabedc5d79afff8ee31..9c894b862d1146fe2a9857f2834c611dc23edeaa 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTestWithInformer.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/ExecutionEventHandlerTestWithInformer.kt @@ -15,6 +15,7 @@ import rocks.theodolite.kubernetes.model.crd.ExecutionCRD import rocks.theodolite.kubernetes.model.crd.ExecutionState import java.io.FileInputStream import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit import java.util.stream.Stream @WithKubernetesTestServer @@ -51,7 +52,7 @@ class ExecutionEventHandlerTestWithInformer { this.controller = mock() this.stateHandler = ExecutionStateHandler(server.client) this.addCountDownLatch = CountDownLatch(1) - this.updateCountDownLatch = CountDownLatch(2) + this.updateCountDownLatch = CountDownLatch(1) this.deleteCountDownLatch = CountDownLatch(1) this.eventHandler = ExecutionEventHandlerWrapper( ExecutionEventHandler(this.controller, this.stateHandler), @@ -103,7 +104,7 @@ class ExecutionEventHandlerTestWithInformer { this.executionClient.inform(eventHandler) // Await informer called - this.addCountDownLatch.await() + this.addCountDownLatch.await(10, TimeUnit.SECONDS) assertEquals(ExecutionState.PENDING, this.executionClient.withName(executionName).get().status.executionState) } @@ -130,7 +131,7 @@ class ExecutionEventHandlerTestWithInformer { // assertEquals(ExecutionStates.RUNNING, this.executionClient.withName(executionName).get().status.executionState) // Await informer called - this.addCountDownLatch.await() + this.addCountDownLatch.await(10, TimeUnit.SECONDS) verify(this.controller).stop(true) assertEquals(ExecutionState.RESTART, this.executionClient.withName(executionName).get().status.executionState) } @@ -138,13 +139,16 @@ class ExecutionEventHandlerTestWithInformer { @Test @DisplayName("Test onUpdate method for execution with no status") fun testOnUpdateWithoutStatus() { + // Start informer + this.executionClient.inform(eventHandler) + // Create first version of execution resource val firstExecutionResource = getExecutionFromSystemResource("k8s-resource-files/test-execution.yaml") val firstExecution = firstExecutionResource.create() val executionName = firstExecution.metadata.name - // Start informer - this.executionClient.inform(eventHandler) + // Await informer called + this.addCountDownLatch.await(10, TimeUnit.SECONDS) // Get execution from server val firstExecutionResponse = this.executionClient.withName(executionName).get() @@ -155,7 +159,7 @@ class ExecutionEventHandlerTestWithInformer { getExecutionFromSystemResource("k8s-resource-files/test-execution-update.yaml").createOrReplace() // Await informer called - this.updateCountDownLatch.await() + this.updateCountDownLatch.await(10, TimeUnit.SECONDS) // Get execution from server and assert that new status matches expected one assertEquals(ExecutionState.PENDING, this.executionClient.withName(executionName).get().status.executionState) } @@ -185,7 +189,7 @@ class ExecutionEventHandlerTestWithInformer { getExecutionFromSystemResource("k8s-resource-files/test-execution-update.yaml").createOrReplace() // Await informer called - this.updateCountDownLatch.await() + this.updateCountDownLatch.await(10, TimeUnit.SECONDS) // Get execution from server and assert that new status matches expected one assertEquals(expectedState, this.executionClient.withName(executionName).get().status.executionState) } @@ -222,7 +226,7 @@ class ExecutionEventHandlerTestWithInformer { assertNull(secondExecutionResponse) // Await informer called - this.deleteCountDownLatch.await() + this.deleteCountDownLatch.await(10, TimeUnit.SECONDS) verify(this.controller).stop(false) } @@ -258,7 +262,7 @@ class ExecutionEventHandlerTestWithInformer { assertNull(secondExecutionResponse) // Await informer called - this.deleteCountDownLatch.await() + this.deleteCountDownLatch.await(10, TimeUnit.SECONDS) verify(this.controller, never()).stop(false) } diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/StateHandlerTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/StateHandlerTest.kt index ebef641d1e0a699ab5e220b0846be654fbefc672..d3447a07dcac8c7429e4b80a927cb92a9b79ea28 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/StateHandlerTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/operator/StateHandlerTest.kt @@ -25,7 +25,7 @@ class StateHandlerTest { fun setUp() { server.before() val executionStream = javaClass.getResourceAsStream("/k8s-resource-files/test-execution.yaml") - val executionResource = server.client.resources(ExecutionCRD::class.java).load(executionStream).get() + val executionResource = server.client.resources(ExecutionCRD::class.java).load(executionStream).item() K8sManager(server.client).deploy(executionResource) } diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcherTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcherTest.kt index e94a513026eee976ff31e2011dab7c8188f8d64c..18604426bbdfef7d10654bc0e015518e65e6f722 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcherTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/GenericResourcePatcherTest.kt @@ -104,6 +104,6 @@ internal class GenericResourcePatcherTest { server.registerResource(serviceMonitorContext) val serviceMonitorStream = javaClass.getResourceAsStream("/k8s-resource-files/test-service-monitor.yaml") - return server.client.load(serviceMonitorStream).get()[0] + return server.client.load(serviceMonitorStream).items().first() } } diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/LabelPatcherTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/LabelPatcherTest.kt index a517992755ce4d57acd7c2c099c3c878d9c1c147..6024834cc6011963305a994d9cb9e63e6a38e744 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/LabelPatcherTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/LabelPatcherTest.kt @@ -96,6 +96,6 @@ internal class LabelPatcherTest: AbstractPatcherTest() { server.registerResource(serviceMonitorContext) val serviceMonitorStream = javaClass.getResourceAsStream("/k8s-resource-files/test-service-monitor.yaml") - return server.client.load(serviceMonitorStream).get()[0] + return server.client.load(serviceMonitorStream).items().first() } } \ No newline at end of file diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/NamePatcherTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/NamePatcherTest.kt index 4f0620a5cdf544440b9c0927a7911edfb2fc84be..4cd9b92798a8c50b8ec37009b0ee9ee30ffa72ab 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/NamePatcherTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/NamePatcherTest.kt @@ -91,6 +91,6 @@ internal class NamePatcherTest: AbstractPatcherTest() { server.registerResource(serviceMonitorContext) val serviceMonitorStream = javaClass.getResourceAsStream("/k8s-resource-files/test-service-monitor.yaml") - return server.client.load(serviceMonitorStream).get()[0] + return server.client.load(serviceMonitorStream).items().first() } } \ No newline at end of file diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceLimitPatcherTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceLimitPatcherTest.kt index 676f512840e2a6c285148ddeb2a12c660933d343..2e067acbee1a9b79181b83712063c6788a4893a2 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceLimitPatcherTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceLimitPatcherTest.kt @@ -143,6 +143,6 @@ class ResourceLimitPatcherTest { } private fun getDeployment(fileName: String): Deployment { - return server.client.apps().deployments().load(javaClass.getResourceAsStream(fileName)).get() + return server.client.apps().deployments().load(javaClass.getResourceAsStream(fileName)).item() } } diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceRequestPatcherTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceRequestPatcherTest.kt index 80102c5481c96fc39ff87ceb8a11f34686e74a59..99d310fd04b9b9ea6c233d6e31b3b482963cbd88 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceRequestPatcherTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/patcher/ResourceRequestPatcherTest.kt @@ -143,7 +143,7 @@ class ResourceRequestPatcherTest { } private fun getDeployment(fileName: String): Deployment { - return server.client.apps().deployments().load(javaClass.getResourceAsStream(fileName)).get() + return server.client.apps().deployments().load(javaClass.getResourceAsStream(fileName)).item() } } \ No newline at end of file diff --git a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactoryTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactoryTest.kt index 5aaac2ecb7439d71417ce80df056e01aa8b8b8f8..6ed51eab45362e36c63b3bb74761db745b44d39d 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactoryTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/kubernetes/slo/SloCheckerFactoryTest.kt @@ -4,7 +4,6 @@ import io.quarkus.test.junit.QuarkusTest import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import rocks.theodolite.core.strategies.Metric @QuarkusTest internal class SloCheckerFactoryTest { @@ -24,8 +23,7 @@ internal class SloCheckerFactoryTest { "threshold" to "1234" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -43,8 +41,7 @@ internal class SloCheckerFactoryTest { "threshold" to "1234" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -62,8 +59,7 @@ internal class SloCheckerFactoryTest { "threshold" to "1234" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -81,8 +77,7 @@ internal class SloCheckerFactoryTest { "threshold" to "1234" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -100,8 +95,7 @@ internal class SloCheckerFactoryTest { "threshold" to "1234" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -119,8 +113,7 @@ internal class SloCheckerFactoryTest { "operator" to "lte", ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -138,8 +131,7 @@ internal class SloCheckerFactoryTest { "threshold" to "12.34" ), 100, - 5, - Metric.DEMAND + 5 ) assertInstanceOf(ExternalSloChecker::class.java, sloChecker) val threshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -160,8 +152,7 @@ internal class SloCheckerFactoryTest { "thresholdRelToLoad" to "0.1" ), 100, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -183,8 +174,7 @@ internal class SloCheckerFactoryTest { "thresholdRelToLoad" to "0.1" ), 100, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -205,8 +195,7 @@ internal class SloCheckerFactoryTest { "thresholdRelToResources" to "0.1" ), 100, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -227,8 +216,7 @@ internal class SloCheckerFactoryTest { "thresholdFromExpression" to "1111" ), 8, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -249,8 +237,7 @@ internal class SloCheckerFactoryTest { "thresholdFromExpression" to "L*5" ), 8, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -271,8 +258,7 @@ internal class SloCheckerFactoryTest { "thresholdFromExpression" to "R*((2^L+4)-60)+111" ), 8, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -290,8 +276,7 @@ internal class SloCheckerFactoryTest { "threshold" to "1234" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -306,8 +291,7 @@ internal class SloCheckerFactoryTest { "threshold" to "1234" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -323,8 +307,7 @@ internal class SloCheckerFactoryTest { "warmup" to "60", ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -339,8 +322,7 @@ internal class SloCheckerFactoryTest { "threshold" to "12.34" ), 100, - 5, - Metric.DEMAND + 5 ) assertInstanceOf(ExternalSloChecker::class.java, sloChecker) val threshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -358,8 +340,7 @@ internal class SloCheckerFactoryTest { "thresholdRelToLoad" to "0.1" ), 100, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -378,8 +359,7 @@ internal class SloCheckerFactoryTest { "thresholdRelToLoad" to "0.1" ), 100, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -397,8 +377,7 @@ internal class SloCheckerFactoryTest { "thresholdRelToResources" to "0.1" ), 100, - 5, - Metric.DEMAND + 5 ) assertTrue(sloChecker is ExternalSloChecker) val computedThreshold = (sloChecker as ExternalSloChecker).metadata["threshold"] @@ -416,8 +395,7 @@ internal class SloCheckerFactoryTest { "ratio" to "0.123" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -432,8 +410,7 @@ internal class SloCheckerFactoryTest { "ratio" to "0.123" ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -449,8 +426,7 @@ internal class SloCheckerFactoryTest { "warmup" to "60", ), 100, - 5, - Metric.DEMAND + 5 ) } } @@ -465,8 +441,7 @@ internal class SloCheckerFactoryTest { "ratio" to "0.123" ), 100, - 5, - Metric.DEMAND + 5 ) assertInstanceOf(ExternalSloChecker::class.java, sloChecker) val threshold = (sloChecker as ExternalSloChecker).metadata["threshold"] diff --git a/theodolite/src/test/resources/resource-teardown-test-files/load-generator-configmap.yaml b/theodolite/src/test/resources/resource-teardown-test-files/load-generator-configmap.yaml index d3392e6fef3d050d5f2b44ab362df1d862ab113f..b20ed32959b78d422ab186c91081e9fc0b3bd9fc 100644 --- a/theodolite/src/test/resources/resource-teardown-test-files/load-generator-configmap.yaml +++ b/theodolite/src/test/resources/resource-teardown-test-files/load-generator-configmap.yaml @@ -3,10 +3,12 @@ metadata: name: load-generator-configmap data: load-generator-file-1.yaml: | + apiVersion: apps/v1 kind: Deployment metadata: name: load-generator-file-1 load-generator-file-2.yaml: | + apiVersion: v1 kind: Service metadata: name: load-generator-file-2 diff --git a/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-1.yaml b/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-1.yaml index e090c0fa94562e7ddf3fe225ed5be0837018199d..1434032d696bfd2c42a94c7c8f90028a4e6fda01 100644 --- a/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-1.yaml +++ b/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-1.yaml @@ -3,10 +3,12 @@ metadata: name: sut-configmap-1 data: sut-file-1.yaml: | + apiVersion: apps/v1 kind: Deployment metadata: name: sut-file-1 sut-file-2.yaml: | + apiVersion: v1 kind: Service metadata: name: sut-file-2 diff --git a/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-2.yaml b/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-2.yaml index 3c52c47d9f96f45058b4a6017d41b29ad25b8468..d17a2c3b2d03227f0eae3cf8b996766f7a2ed05f 100644 --- a/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-2.yaml +++ b/theodolite/src/test/resources/resource-teardown-test-files/sut-configmap-2.yaml @@ -3,6 +3,7 @@ metadata: name: sut-configmap-2 data: sut-file-3.yaml: | + apiVersion: apps/v1 kind: Deployment metadata: name: sut-file-3