From 7cf3de302a9247975bdfe9108f63a356ebbcdcca Mon Sep 17 00:00:00 2001 From: "stu126940@mail.uni-kiel.de" <stu126940@mail.uni-kiel.de> Date: Mon, 8 Mar 2021 12:37:47 +0100 Subject: [PATCH] Minor code changes, add test for ResourcePatcher --- .../patcher/ResourceLimitPatcher.kt | 17 ++-- .../patcher/ResourceRequestPatcher.kt | 16 ++-- .../resources/testYaml/cpu-deployment.yaml | 56 +++++++++++++ .../testYaml/cpu-memory-deployment.yaml | 58 +++++++++++++ .../resources/testYaml/memory-deployment.yaml | 56 +++++++++++++ .../testYaml/no-resources-deployment.yaml | 51 +++++++++++ .../theodolite/ResourceLimitPatcherTest.kt | 84 +++++++++++++++++++ .../theodolite/ResourceRequestPatcherTest.kt | 84 +++++++++++++++++++ 8 files changed, 408 insertions(+), 14 deletions(-) create mode 100644 theodolite-quarkus/src/main/resources/testYaml/cpu-deployment.yaml create mode 100644 theodolite-quarkus/src/main/resources/testYaml/cpu-memory-deployment.yaml create mode 100644 theodolite-quarkus/src/main/resources/testYaml/memory-deployment.yaml create mode 100644 theodolite-quarkus/src/main/resources/testYaml/no-resources-deployment.yaml create mode 100644 theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt create mode 100644 theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt index d3ca8e656..752e4703b 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt @@ -4,6 +4,7 @@ import io.fabric8.kubernetes.api.model.KubernetesResource import io.fabric8.kubernetes.api.model.Quantity import io.fabric8.kubernetes.api.model.ResourceRequirements import io.fabric8.kubernetes.api.model.apps.Deployment +import javax.validation.constraints.Null class ResourceLimitPatcher( private val k8sResource: KubernetesResource, @@ -14,19 +15,21 @@ class ResourceLimitPatcher( override fun <String> patch(value: String) { if (k8sResource is Deployment) { k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach { - try { - if (it.resources.limits.isEmpty()) { + when { + it.resources == null -> { + val resource = ResourceRequirements() + resource.limits = mapOf(limitedResource to Quantity(value as kotlin.String)) + it.resources = resource + } + it.resources.limits.isEmpty() -> { it.resources.limits = mapOf(limitedResource to Quantity(value as kotlin.String)) - } else { + } + else -> { val values = mutableMapOf<kotlin.String, Quantity>() it.resources.limits.forEach { entry -> values[entry.key] = entry.value } values[limitedResource] = Quantity(value as kotlin.String) it.resources.limits = values } - } catch (e: IllegalStateException) { - val resource = ResourceRequirements() - resource.limits = mapOf(limitedResource to Quantity(value as kotlin.String)) - it.resources = resource } } } diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt index d6090875e..865d350bb 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt @@ -14,19 +14,21 @@ class ResourceRequestPatcher( override fun <String> patch(value: String) { if (k8sResource is Deployment) { k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach { - try { - if (it.resources.requests.isEmpty()) { + when { + it.resources == null -> { + val resource = ResourceRequirements() + resource.requests = mapOf(requestedResource to Quantity(value as kotlin.String)) + it.resources = resource + } + it.resources.requests.isEmpty() -> { it.resources.requests = mapOf(requestedResource to Quantity(value as kotlin.String)) - } else { + } + else -> { val values = mutableMapOf<kotlin.String, Quantity>() it.resources.requests.forEach { entry -> values[entry.key] = entry.value } values[requestedResource] = Quantity(value as kotlin.String) it.resources.requests = values } - } catch (e: IllegalStateException) { - val resource = ResourceRequirements() - resource.requests = mapOf(requestedResource to Quantity(value as kotlin.String)) - it.resources = resource } } } diff --git a/theodolite-quarkus/src/main/resources/testYaml/cpu-deployment.yaml b/theodolite-quarkus/src/main/resources/testYaml/cpu-deployment.yaml new file mode 100644 index 000000000..984564894 --- /dev/null +++ b/theodolite-quarkus/src/main/resources/testYaml/cpu-deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: titan-ccp-aggregation +spec: + selector: + matchLabels: + app: titan-ccp-aggregation + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-aggregation + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: uc-application + image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest + ports: + - containerPort: 5555 + name: jmx + env: + - name: KAFKA_BOOTSTRAP_SERVERS + value: "my-confluent-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://my-confluent-cp-schema-registry:8081" + - name: JAVA_OPTS + value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=5555" + - name: COMMIT_INTERVAL_MS # Set as default for the applications + value: "100" + resources: + limits: + cpu: 1000m + requests: + cpu: 500m + - name: prometheus-jmx-exporter + image: "solsson/kafka-prometheus-jmx-exporter@sha256:6f82e2b0464f50da8104acd7363fb9b995001ddff77d248379f8788e78946143" + command: + - java + - -XX:+UnlockExperimentalVMOptions + - -XX:+UseCGroupMemoryLimitForHeap + - -XX:MaxRAMFraction=1 + - -XshowSettings:vm + - -jar + - jmx_prometheus_httpserver.jar + - "5556" + - /etc/jmx-aggregation/jmx-kafka-prometheus.yml + ports: + - containerPort: 5556 + volumeMounts: + - name: jmx-config + mountPath: /etc/jmx-aggregation + volumes: + - name: jmx-config + configMap: + name: aggregation-jmx-configmap \ No newline at end of file diff --git a/theodolite-quarkus/src/main/resources/testYaml/cpu-memory-deployment.yaml b/theodolite-quarkus/src/main/resources/testYaml/cpu-memory-deployment.yaml new file mode 100644 index 000000000..eaae989ab --- /dev/null +++ b/theodolite-quarkus/src/main/resources/testYaml/cpu-memory-deployment.yaml @@ -0,0 +1,58 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: titan-ccp-aggregation +spec: + selector: + matchLabels: + app: titan-ccp-aggregation + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-aggregation + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: uc-application + image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest + ports: + - containerPort: 5555 + name: jmx + env: + - name: KAFKA_BOOTSTRAP_SERVERS + value: "my-confluent-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://my-confluent-cp-schema-registry:8081" + - name: JAVA_OPTS + value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=5555" + - name: COMMIT_INTERVAL_MS # Set as default for the applications + value: "100" + resources: + limits: + memory: 4Gi + cpu: 1000m + requests: + memory: 2Gi + cpu: 500m + - name: prometheus-jmx-exporter + image: "solsson/kafka-prometheus-jmx-exporter@sha256:6f82e2b0464f50da8104acd7363fb9b995001ddff77d248379f8788e78946143" + command: + - java + - -XX:+UnlockExperimentalVMOptions + - -XX:+UseCGroupMemoryLimitForHeap + - -XX:MaxRAMFraction=1 + - -XshowSettings:vm + - -jar + - jmx_prometheus_httpserver.jar + - "5556" + - /etc/jmx-aggregation/jmx-kafka-prometheus.yml + ports: + - containerPort: 5556 + volumeMounts: + - name: jmx-config + mountPath: /etc/jmx-aggregation + volumes: + - name: jmx-config + configMap: + name: aggregation-jmx-configmap \ No newline at end of file diff --git a/theodolite-quarkus/src/main/resources/testYaml/memory-deployment.yaml b/theodolite-quarkus/src/main/resources/testYaml/memory-deployment.yaml new file mode 100644 index 000000000..7af278b8c --- /dev/null +++ b/theodolite-quarkus/src/main/resources/testYaml/memory-deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: titan-ccp-aggregation +spec: + selector: + matchLabels: + app: titan-ccp-aggregation + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-aggregation + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: uc-application + image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest + ports: + - containerPort: 5555 + name: jmx + env: + - name: KAFKA_BOOTSTRAP_SERVERS + value: "my-confluent-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://my-confluent-cp-schema-registry:8081" + - name: JAVA_OPTS + value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=5555" + - name: COMMIT_INTERVAL_MS # Set as default for the applications + value: "100" + resources: + limits: + memory: 4Gi + requests: + memory: 2Gi + - name: prometheus-jmx-exporter + image: "solsson/kafka-prometheus-jmx-exporter@sha256:6f82e2b0464f50da8104acd7363fb9b995001ddff77d248379f8788e78946143" + command: + - java + - -XX:+UnlockExperimentalVMOptions + - -XX:+UseCGroupMemoryLimitForHeap + - -XX:MaxRAMFraction=1 + - -XshowSettings:vm + - -jar + - jmx_prometheus_httpserver.jar + - "5556" + - /etc/jmx-aggregation/jmx-kafka-prometheus.yml + ports: + - containerPort: 5556 + volumeMounts: + - name: jmx-config + mountPath: /etc/jmx-aggregation + volumes: + - name: jmx-config + configMap: + name: aggregation-jmx-configmap \ No newline at end of file diff --git a/theodolite-quarkus/src/main/resources/testYaml/no-resources-deployment.yaml b/theodolite-quarkus/src/main/resources/testYaml/no-resources-deployment.yaml new file mode 100644 index 000000000..0687a3e04 --- /dev/null +++ b/theodolite-quarkus/src/main/resources/testYaml/no-resources-deployment.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: titan-ccp-aggregation +spec: + selector: + matchLabels: + app: titan-ccp-aggregation + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-aggregation + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: uc-application + image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest + ports: + - containerPort: 5555 + name: jmx + env: + - name: KAFKA_BOOTSTRAP_SERVERS + value: "my-confluent-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://my-confluent-cp-schema-registry:8081" + - name: JAVA_OPTS + value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=5555" + - name: COMMIT_INTERVAL_MS # Set as default for the applications + value: "100" + - name: prometheus-jmx-exporter + image: "solsson/kafka-prometheus-jmx-exporter@sha256:6f82e2b0464f50da8104acd7363fb9b995001ddff77d248379f8788e78946143" + command: + - java + - -XX:+UnlockExperimentalVMOptions + - -XX:+UseCGroupMemoryLimitForHeap + - -XX:MaxRAMFraction=1 + - -XshowSettings:vm + - -jar + - jmx_prometheus_httpserver.jar + - "5556" + - /etc/jmx-aggregation/jmx-kafka-prometheus.yml + ports: + - containerPort: 5556 + volumeMounts: + - name: jmx-config + mountPath: /etc/jmx-aggregation + volumes: + - name: jmx-config + configMap: + name: aggregation-jmx-configmap \ No newline at end of file diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt new file mode 100644 index 000000000..3e7be5bd9 --- /dev/null +++ b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt @@ -0,0 +1,84 @@ +package theodolite + +import io.fabric8.kubernetes.api.model.apps.Deployment +import io.fabric8.kubernetes.client.DefaultKubernetesClient +import io.quarkus.test.junit.QuarkusTest +import io.smallrye.common.constraint.Assert.assertTrue +import org.junit.jupiter.api.Test +import theodolite.k8s.K8sResourceLoader +import theodolite.patcher.PatcherManager +import theodolite.util.PatcherDefinition + +/** + * Resource patcher test + * + * This class tested 4 scenarios for the ResourceLimitPatcher and the ResourceRequestPatcher. The different test cases specifies four possible situations: + * Case 1: In the given YAML declaration memory and cpu are defined + * Case 2: In the given YAML declaration only cpu is defined + * Case 3: In the given YAML declaration only memory is defined + * Case 4: In the given YAML declaration neither `Resource Request` nor `Request Limit` is defined + */ +@QuarkusTest +class ResourceLimitPatcherTest { + val testPath = "./src/main/resources/testYaml/" + val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace("")) + val manager = PatcherManager() + + + fun applyTest(fileName: String) { + val CPUValue = "50m" + val MEMValue = "3Gi" + val k8sResource = loader.loadK8sResource("Deployment", testPath + fileName) as Deployment + + val defCPU = PatcherDefinition() + defCPU.variableName = "cpu" + defCPU.resource = "cpu-memory-deployment.yaml" + defCPU.container = "uc-application" + defCPU.type = "ResourceLimitPatcher" + + val defMEM = PatcherDefinition() + defMEM.variableName = "memory" + defMEM.resource = "cpu-memory-deployment.yaml" + defMEM.container = "uc-application" + defMEM.type = "ResourceLimitPatcher" + + manager.applyPatcher( + patcherDefinition = listOf(defCPU), + resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)), + value = CPUValue + ) + manager.applyPatcher( + patcherDefinition = listOf(defMEM), + resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)), + value = MEMValue + ) + + k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container } + .forEach { + println(it) + assertTrue(it.resources.limits["cpu"].toString() == "$CPUValue") + assertTrue(it.resources.limits["memory"].toString() == "$MEMValue") + } + } + + @Test + fun case1() { + // Case 1: In the given YAML declaration memory and cpu are defined + applyTest("cpu-memory-deployment.yaml") + } + @Test + fun case2() { + // Case 2: In the given YAML declaration only cpu is defined + applyTest("cpu-deployment.yaml") + } + @Test + fun case3() { + // Case 3: In the given YAML declaration only memory is defined + applyTest("memory-deployment.yaml") + } + @Test + fun case4() { + // Case 4: In the given YAML declaration neither `Resource Request` nor `Request Limit` is defined + applyTest("no-resources-deployment.yaml") + } +} \ No newline at end of file diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt new file mode 100644 index 000000000..10ff5320e --- /dev/null +++ b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt @@ -0,0 +1,84 @@ +package theodolite + +import io.fabric8.kubernetes.api.model.apps.Deployment +import io.fabric8.kubernetes.client.DefaultKubernetesClient +import io.quarkus.test.junit.QuarkusTest +import io.smallrye.common.constraint.Assert.assertTrue +import org.junit.jupiter.api.Test +import theodolite.k8s.K8sResourceLoader +import theodolite.patcher.PatcherManager +import theodolite.util.PatcherDefinition + +/** + * Resource patcher test + * + * This class tested 4 scenarios for the ResourceLimitPatcher and the ResourceRequestPatcher. The different test cases specifies four possible situations: + * Case 1: In the given YAML declaration memory and cpu are defined + * Case 2: In the given YAML declaration only cpu is defined + * Case 3: In the given YAML declaration only memory is defined + * Case 4: In the given YAML declaration neither `Resource Request` nor `Request Limit` is defined + */ +@QuarkusTest +class ResourceRequestPatcherTest { + val testPath = "./src/main/resources/testYaml/" + val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace("")) + val manager = PatcherManager() + + + fun applyTest(fileName: String) { + val CPUValue = "50m" + val MEMValue = "3Gi" + val k8sResource = loader.loadK8sResource("Deployment", testPath + fileName) as Deployment + + val defCPU = PatcherDefinition() + defCPU.variableName = "cpu" + defCPU.resource = "cpu-memory-deployment.yaml" + defCPU.container = "uc-application" + defCPU.type = "ResourceRequestPatcher" + + val defMEM = PatcherDefinition() + defMEM.variableName = "memory" + defMEM.resource = "cpu-memory-deployment.yaml" + defMEM.container = "uc-application" + defMEM.type = "ResourceRequestPatcher" + + manager.applyPatcher( + patcherDefinition = listOf(defCPU), + resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)), + value = CPUValue + ) + manager.applyPatcher( + patcherDefinition = listOf(defMEM), + resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)), + value = MEMValue + ) + + k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container } + .forEach { + println(it) + assertTrue(it.resources.requests["cpu"].toString() == "$CPUValue") + assertTrue(it.resources.requests["memory"].toString() == "$MEMValue") + } + } + + @Test + fun case1() { + // Case 1: In the given YAML declaration memory and cpu are defined + applyTest("cpu-memory-deployment.yaml") + } + @Test + fun case2() { + // Case 2: In the given YAML declaration only cpu is defined + applyTest("cpu-deployment.yaml") + } + @Test + fun case3() { + // Case 3: In the given YAML declaration only memory is defined + applyTest("memory-deployment.yaml") + } + @Test + fun case4() { + // Case 4: In the given YAML declaration neither `Resource Request` nor `Request Limit` is defined + applyTest("no-resources-deployment.yaml") + } +} \ No newline at end of file -- GitLab