Skip to content
Snippets Groups Projects
Commit 7cf3de30 authored by Benedikt Wetzel's avatar Benedikt Wetzel
Browse files

Minor code changes, add test for ResourcePatcher

parent 9bf2b5f6
No related branches found
No related tags found
4 merge requests!159Re-implementation of Theodolite with Kotlin/Quarkus,!157Update Graal Image in CI pipeline,!85Introduce new Benchmark class and Patcher,!83WIP: Re-implementation of Theodolite with Kotlin/Quarkus
...@@ -4,6 +4,7 @@ import io.fabric8.kubernetes.api.model.KubernetesResource ...@@ -4,6 +4,7 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
import io.fabric8.kubernetes.api.model.Quantity import io.fabric8.kubernetes.api.model.Quantity
import io.fabric8.kubernetes.api.model.ResourceRequirements import io.fabric8.kubernetes.api.model.ResourceRequirements
import io.fabric8.kubernetes.api.model.apps.Deployment import io.fabric8.kubernetes.api.model.apps.Deployment
import javax.validation.constraints.Null
class ResourceLimitPatcher( class ResourceLimitPatcher(
private val k8sResource: KubernetesResource, private val k8sResource: KubernetesResource,
...@@ -14,19 +15,21 @@ class ResourceLimitPatcher( ...@@ -14,19 +15,21 @@ class ResourceLimitPatcher(
override fun <String> patch(value: String) { override fun <String> patch(value: String) {
if (k8sResource is Deployment) { if (k8sResource is Deployment) {
k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach { k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
try { when {
if (it.resources.limits.isEmpty()) { 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)) it.resources.limits = mapOf(limitedResource to Quantity(value as kotlin.String))
} else { }
else -> {
val values = mutableMapOf<kotlin.String, Quantity>() val values = mutableMapOf<kotlin.String, Quantity>()
it.resources.limits.forEach { entry -> values[entry.key] = entry.value } it.resources.limits.forEach { entry -> values[entry.key] = entry.value }
values[limitedResource] = Quantity(value as kotlin.String) values[limitedResource] = Quantity(value as kotlin.String)
it.resources.limits = values it.resources.limits = values
} }
} catch (e: IllegalStateException) {
val resource = ResourceRequirements()
resource.limits = mapOf(limitedResource to Quantity(value as kotlin.String))
it.resources = resource
} }
} }
} }
......
...@@ -14,19 +14,21 @@ class ResourceRequestPatcher( ...@@ -14,19 +14,21 @@ class ResourceRequestPatcher(
override fun <String> patch(value: String) { override fun <String> patch(value: String) {
if (k8sResource is Deployment) { if (k8sResource is Deployment) {
k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach { k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
try { when {
if (it.resources.requests.isEmpty()) { 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)) it.resources.requests = mapOf(requestedResource to Quantity(value as kotlin.String))
} else { }
else -> {
val values = mutableMapOf<kotlin.String, Quantity>() val values = mutableMapOf<kotlin.String, Quantity>()
it.resources.requests.forEach { entry -> values[entry.key] = entry.value } it.resources.requests.forEach { entry -> values[entry.key] = entry.value }
values[requestedResource] = Quantity(value as kotlin.String) values[requestedResource] = Quantity(value as kotlin.String)
it.resources.requests = values it.resources.requests = values
} }
} catch (e: IllegalStateException) {
val resource = ResourceRequirements()
resource.requests = mapOf(requestedResource to Quantity(value as kotlin.String))
it.resources = resource
} }
} }
} }
......
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
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
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
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
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
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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment