Skip to content
Snippets Groups Projects
Commit 585f1db7 authored by Benedikt Wetzel's avatar Benedikt Wetzel Committed by Sören Henning
Browse files

Add for stateHandler, small fixes

parent 13d08d28
No related branches found
No related tags found
4 merge requests!159Re-implementation of Theodolite with Kotlin/Quarkus,!157Update Graal Image in CI pipeline,!154Add more Kuberntes related tests,!83WIP: Re-implementation of Theodolite with Kotlin/Quarkus
Showing
with 174 additions and 35 deletions
......@@ -32,6 +32,8 @@ dependencies {
testImplementation 'io.rest-assured:rest-assured'
testImplementation 'org.junit-pioneer:junit-pioneer:1.4.0'
testImplementation group: 'io.fabric8', name: 'kubernetes-server-mock', version: '4.6.0'
testImplementation (group: 'io.fabric8', name: 'kubernetes-server-mock', version: '5.4.1'){force = true}
......
......@@ -29,7 +29,7 @@ class ExecutionStateHandler(context: CustomResourceDefinitionContext, val client
private fun getDurationLambda() = { cr: CustomResource ->
var execState = ""
if (cr is ExecutionCRD) { execState = cr.status.executionState }
if (cr is ExecutionCRD) { execState = cr.status.executionDuration }
execState
}
......@@ -43,9 +43,9 @@ class ExecutionStateHandler(context: CustomResourceDefinitionContext, val client
return States.values().firstOrNull { it.value == status }
}
fun setDurationState(resourceName: String, duration: Duration) {
fun setDurationState(resourceName: String, duration: Duration): Boolean {
setState(resourceName) { cr -> if (cr is ExecutionCRD) cr.status.executionDuration = durationToK8sString(duration); cr }
blockUntilStateIsSet(resourceName, durationToK8sString(duration), getDurationLambda())
return blockUntilStateIsSet(resourceName, durationToK8sString(duration), getDurationLambda())
}
fun getDurationState(resourceName: String): String? {
......
......@@ -2,12 +2,11 @@ package theodolite.k8s
import io.fabric8.kubernetes.client.CustomResource
import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
import mu.KotlinLogging
private val logger = KotlinLogging.logger {}
class ServiceMonitorWrapper(private val serviceMonitor: Map<String, String>) : CustomResource() {
class CustomResourceWrapper(val crAsMap: Map<String, String>, private val context: CustomResourceDefinitionContext) : CustomResource() {
/**
* Deploy a service monitor
*
......@@ -16,14 +15,9 @@ class ServiceMonitorWrapper(private val serviceMonitor: Map<String, String>) : C
* @throws java.io.IOException if the resource could not be deployed.
*/
fun deploy(client: NamespacedKubernetesClient) {
val serviceMonitorContext = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "monitoring.coreos.com",
plural = "servicemonitors"
)
client.customResource(serviceMonitorContext)
.createOrReplace(client.configuration.namespace, this.serviceMonitor as Map<String, Any>)
client.customResource(this.context)
.createOrReplace(client.configuration.namespace, this.crAsMap as Map<String, Any>)
}
/**
......@@ -32,14 +26,8 @@ class ServiceMonitorWrapper(private val serviceMonitor: Map<String, String>) : C
* @param client a namespaced Kubernetes client which are used to delete the CR object.
*/
fun delete(client: NamespacedKubernetesClient) {
val serviceMonitorContext = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "monitoring.coreos.com",
plural = "servicemonitors"
)
try {
client.customResource(serviceMonitorContext)
client.customResource(this.context)
.delete(client.configuration.namespace, this.getServiceMonitorName())
} catch (e: Exception) {
logger.warn { "Could not delete service monitor" }
......@@ -50,12 +38,12 @@ class ServiceMonitorWrapper(private val serviceMonitor: Map<String, String>) : C
* @throws NullPointerException if name or metadata is null
*/
fun getServiceMonitorName(): String {
val smAsMap = this.serviceMonitor["metadata"]!! as Map<String, String>
return smAsMap["name"]!!
val metadataAsMap = this.crAsMap["metadata"]!! as Map<String, String>
return metadataAsMap["name"]!!
}
fun getLabels(): Map<String, String>{
val smAsMap = this.serviceMonitor["metadata"]!! as Map<String, String>
return smAsMap["labels"]!! as Map<String, String>
val metadataAsMap = this.crAsMap["metadata"]!! as Map<String, String>
return metadataAsMap["labels"]!! as Map<String, String>
}
}
......@@ -31,7 +31,7 @@ class K8sManager(private val client: NamespacedKubernetesClient) {
this.client.configMaps().createOrReplace(resource)
is StatefulSet ->
this.client.apps().statefulSets().createOrReplace(resource)
is ServiceMonitorWrapper -> resource.deploy(client)
is CustomResourceWrapper -> resource.deploy(client)
else -> throw IllegalArgumentException("Unknown Kubernetes resource.")
}
}
......@@ -58,7 +58,7 @@ class K8sManager(private val client: NamespacedKubernetesClient) {
blockUntilPodsDeleted(label)
logger.info { "StatefulSet '$resource.metadata.name' deleted." }
}
is ServiceMonitorWrapper -> resource.delete(client)
is CustomResourceWrapper -> resource.delete(client)
else -> throw IllegalArgumentException("Unknown Kubernetes resource.")
}
}
......
......@@ -31,13 +31,40 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) {
* @param path of the yaml file
* @return CustomResource from fabric8
*/
private fun loadServiceMonitor(path: String): ServiceMonitorWrapper {
return loadGenericResource(path) { x: String ->
ServiceMonitorWrapper(
private fun loadServiceMonitor(path: String): CustomResourceWrapper {
val context = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "monitoring.coreos.com",
plural = "servicemonitors"
)
return loadGenericResource(path) {
CustomResourceWrapper(
YamlParser().parse(
path,
HashMap<String, String>()::class.java
)!!,
context
)
}
}
private fun loadExecution(path: String): KubernetesResource {
val context = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "theodolite.com",
plural = "executions"
)
return loadGenericResource(path) {
CustomResourceWrapper(
YamlParser().parse(
path,
HashMap<String, String>()::class.java
)!!
)!!,
context
)
}
}
......@@ -107,6 +134,7 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) {
"ServiceMonitor" -> loadServiceMonitor(path)
"ConfigMap" -> loadConfigmap(path)
"StatefulSet" -> loadStatefulSet(path)
"Execution" -> loadExecution(path)
else -> {
logger.error { "Error during loading of unspecified resource Kind" }
throw java.lang.IllegalArgumentException("error while loading resource with kind: $kind")
......
package theodolite.execution.operator
class ControllerTest {
}
\ No newline at end of file
package theodolite.execution.operator
import io.fabric8.kubernetes.client.server.mock.KubernetesServer
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.DisplayName
import org.junit.jupiter.api.Test
import theodolite.k8s.K8sContextFactory
import theodolite.k8s.K8sManager
import theodolite.k8s.K8sResourceLoader
import theodolite.model.crd.States
import java.time.Duration
class StateHandlerTest {
private val testResourcePath = "./src/test/resources/k8s-resource-files/"
private val server = KubernetesServer(false,true)
private val context = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "theodolite.com",
plural = "executions"
)
@BeforeEach
fun setUp() {
server.before()
val executionResource = K8sResourceLoader(server.client)
.loadK8sResource("Execution", testResourcePath + "test-execution.yaml")
K8sManager(server.client).deploy(executionResource)
}
@AfterEach
fun tearDown() {
server.after()
}
@Test
@DisplayName("Test set and get of the execution state")
fun executionStatusTest() {
val handler = ExecutionStateHandler(client = server.client, context = context)
assertTrue(handler.setExecutionState("example-execution", States.INTERRUPTED))
assertEquals(States.INTERRUPTED,handler.getExecutionState("example-execution") )
}
@Test
@DisplayName("Test set and get of the execution duration state")
fun durationStatusTest() {
val handler = ExecutionStateHandler(client = server.client, context = context)
assertTrue(handler.setDurationState("example-execution", Duration.ofMillis(100)))
assertEquals("0s",handler.getDurationState("example-execution") )
}
}
\ No newline at end of file
package theodolite.k8s
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import io.fabric8.kubernetes.api.model.*
import io.fabric8.kubernetes.api.model.apps.Deployment
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder
......@@ -19,7 +20,9 @@ import org.junit.jupiter.api.Test
private val logger = KotlinLogging.logger {}
@QuarkusTest
@JsonIgnoreProperties(ignoreUnknown = true)
class K8sManagerTest {
@JsonIgnoreProperties(ignoreUnknown = true)
private final val server = KubernetesServer(false,true)
private final val testResourcePath = "./src/test/resources/k8s-resource-files/"
......@@ -147,5 +150,34 @@ class K8sManagerTest {
assertEquals(0,serviceMonitors.length())
}
@Test
@DisplayName("Test handling of Executions")
@JsonIgnoreProperties(ignoreUnknown = true)
fun handleExecutionTest() {
val manager = K8sManager(server.client)
val servicemonitor = K8sResourceLoader(server.client)
.loadK8sResource("Execution", testResourcePath + "test-execution.yaml")
manager.deploy(servicemonitor)
val context = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "theodolite.com",
plural = "executions"
)
var serviceMonitors = JSONObject(server.client.customResource(context).list())
.getJSONArray("items")
assertEquals(1,serviceMonitors.length())
assertEquals("example-execution", serviceMonitors.getJSONObject(0).getJSONObject("metadata").getString("name"))
manager.remove(servicemonitor)
serviceMonitors = JSONObject(server.client.customResource(context).list())
.getJSONArray("items")
assertEquals(0,serviceMonitors.length())
}
}
\ No newline at end of file
......@@ -21,13 +21,11 @@ class K8sResourceLoaderTest {
@BeforeEach
fun setUp() {
server.before()
}
@AfterEach
fun tearDown() {
server.after()
}
@Test
......@@ -76,8 +74,8 @@ class K8sResourceLoaderTest {
val loader = K8sResourceLoader(server.client)
val resource = loader.loadK8sResource("ServiceMonitor", testResourcePath + "test-service-monitor.yaml")
assertTrue(resource is ServiceMonitorWrapper)
if (resource is ServiceMonitorWrapper) {
assertTrue(resource is CustomResourceWrapper)
if (resource is CustomResourceWrapper) {
assertEquals(resource.getServiceMonitorName(),"test-service-monitor")
}
......
apiVersion: theodolite.com/v1
kind: execution
metadata:
name: example-execution
spec:
name: test
benchmark: "uc1-kstreams"
load:
loadType: "NumSensors"
loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
resources:
resourceType: "Instances"
resourceValues: [1, 2, 3, 4, 5]
slos:
- sloType: "lag trend"
threshold: 2000
prometheusUrl: "http://prometheus-operated:9090"
externalSloUrl: "http://localhost:80/evaluate-slope"
offset: 0
warmup: 60 # in seconds
execution:
strategy: "LinearSearch"
duration: 300 # in seconds
repetitions: 1
loadGenerationDelay: 30 # in seconds
restrictions:
- "LowerBound"
configOverrides: []
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