Skip to content
Snippets Groups Projects
Commit f6e1dd05 authored by Sören Henning's avatar Sören Henning
Browse files

Merge branch 'theodolite-kotlin' into rename-gradle-project

parents 0f2052f1 87d70619
No related branches found
No related tags found
2 merge requests!161Rename Theodolite Gradle project,!159Re-implementation of Theodolite with Kotlin/Quarkus
Pipeline #3849 passed
package theodolite.execution.operator
import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.MixedOperation
import io.fabric8.kubernetes.client.dsl.Resource
import mu.KotlinLogging
......@@ -17,15 +16,12 @@ private val logger = KotlinLogging.logger {}
/**
* The controller implementation for Theodolite.
*
* @see NamespacedKubernetesClient
* @see CustomResourceDefinitionContext
* @see BenchmarkExecution
* @see KubernetesBenchmark
* @see ConcurrentLinkedDeque
*/
class TheodoliteController(
private val namespace: String,
val path: String,
private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, Resource<ExecutionCRD>>,
private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>,
......@@ -116,11 +112,10 @@ class TheodoliteController(
*/
private fun getBenchmarks(): List<KubernetesBenchmark> {
return this.benchmarkCRDClient
.inNamespace(namespace)
.list()
.items
.map { it.spec.name = it.metadata.name; it }
.map { it.spec.path = path; it }
.map { it.spec.path = path; it } // TODO check if we can remove the path field from the KubernetesBenchmark
.map { it.spec }
}
......@@ -140,7 +135,6 @@ class TheodoliteController(
.map { it.name }
return executionCRDClient
.inNamespace(namespace)
.list()
.items
.asSequence()
......
......@@ -4,6 +4,7 @@ import io.fabric8.kubernetes.client.DefaultKubernetesClient
import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.MixedOperation
import io.fabric8.kubernetes.client.dsl.Resource
import io.fabric8.kubernetes.client.informers.SharedInformerFactory
import io.fabric8.kubernetes.internal.KubernetesDeserializer
import mu.KotlinLogging
import theodolite.model.crd.BenchmarkCRD
......@@ -27,7 +28,11 @@ private val logger = KotlinLogging.logger {}
*/
class TheodoliteOperator {
private val namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
private val appResource = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
private lateinit var controller: TheodoliteController
private lateinit var executionStateHandler: ExecutionStateHandler
fun start() {
......@@ -41,7 +46,7 @@ class TheodoliteOperator {
/**
* Start the operator.
*/
private fun startOperator() {
private fun startOperator() {
logger.info { "Using $namespace as namespace." }
client.use {
KubernetesDeserializer.registerCustomKind(
......@@ -56,56 +61,75 @@ class TheodoliteOperator {
BenchmarkCRD::class.java
)
val executionCRDClient: MixedOperation<
ExecutionCRD,
BenchmarkExecutionList,
Resource<ExecutionCRD>>
= client.customResources(
ExecutionCRD::class.java,
BenchmarkExecutionList::class.java
)
ClusterSetup(
executionCRDClient = getExecutionClient(client),
benchmarkCRDClient = getBenchmarkClient(client),
client = client
).clearClusterState()
val benchmarkCRDClient: MixedOperation<
BenchmarkCRD,
KubernetesBenchmarkList,
Resource<BenchmarkCRD>>
= client.customResources(
BenchmarkCRD::class.java,
KubernetesBenchmarkList::class.java
)
getController(
client = client,
executionStateHandler = getExecutionStateHandler(client = client)
).run()
getExecutionEventHandler(client).startAllRegisteredInformers()
}
}
val executionStateHandler = ExecutionStateHandler(
client = client)
val appResource = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
val controller =
TheodoliteController(
namespace = client.namespace,
path = appResource,
benchmarkCRDClient = benchmarkCRDClient,
executionCRDClient = executionCRDClient,
executionStateHandler = executionStateHandler)
val informerFactory = client.informers()
val informerExecution = informerFactory.sharedIndexInformerForCustomResource(
ExecutionCRD::class.java,
BenchmarkExecutionList::class.java,
RESYNC_PERIOD
)
fun getExecutionEventHandler(client: NamespacedKubernetesClient): SharedInformerFactory {
val factory = client.informers()
.inNamespace(client.namespace)
informerExecution.addEventHandler(ExecutionHandler(
factory.sharedIndexInformerForCustomResource(
ExecutionCRD::class.java,
RESYNC_PERIOD
).addEventHandler(
ExecutionHandler(
controller = controller,
stateHandler = executionStateHandler))
ClusterSetup(
executionCRDClient = executionCRDClient,
benchmarkCRDClient = benchmarkCRDClient,
client = client
).clearClusterState()
stateHandler = ExecutionStateHandler(client)
)
)
return factory
}
informerFactory.startAllRegisteredInformers()
controller.run()
fun getExecutionStateHandler(client: NamespacedKubernetesClient): ExecutionStateHandler {
if (!::executionStateHandler.isInitialized) {
this.executionStateHandler = ExecutionStateHandler(client = client)
}
return executionStateHandler
}
fun getController(
client: NamespacedKubernetesClient,
executionStateHandler: ExecutionStateHandler
): TheodoliteController {
if (!::controller.isInitialized) {
this.controller = TheodoliteController(
path = this.appResource,
benchmarkCRDClient = getBenchmarkClient(client),
executionCRDClient = getExecutionClient(client),
executionStateHandler = executionStateHandler
)
}
return this.controller
}
private fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation<
ExecutionCRD,
BenchmarkExecutionList,
Resource<ExecutionCRD>> {
return client.customResources(
ExecutionCRD::class.java,
BenchmarkExecutionList::class.java
)
}
private fun getBenchmarkClient(client: NamespacedKubernetesClient): MixedOperation<
BenchmarkCRD,
KubernetesBenchmarkList,
Resource<BenchmarkCRD>> {
return client.customResources(
BenchmarkCRD::class.java,
KubernetesBenchmarkList::class.java
)
}
}
package theodolite.execution.operator
import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.MixedOperation
import io.fabric8.kubernetes.client.dsl.Resource
import io.fabric8.kubernetes.internal.KubernetesDeserializer
import theodolite.model.crd.BenchmarkCRD
import theodolite.model.crd.BenchmarkExecutionList
import theodolite.model.crd.ExecutionCRD
import theodolite.model.crd.KubernetesBenchmarkList
private const val SCOPE = "Namespaced"
private const val EXECUTION_SINGULAR = "execution"
private const val EXECUTION_PLURAL = "executions"
private const val BENCHMARK_SINGULAR = "benchmark"
private const val BENCHMARK_PLURAL = "benchmarks"
private const val API_VERSION = "v1"
private const val GROUP = "theodolite.com"
class ControllerDummy(client: NamespacedKubernetesClient) {
private var controller: TheodoliteController
val executionStateHandler = ExecutionStateHandler(
client = client
)
fun getController(): TheodoliteController {
return this.controller
}
init {
KubernetesDeserializer.registerCustomKind(
"$GROUP/$API_VERSION",
EXECUTION_SINGULAR,
ExecutionCRD::class.java
)
KubernetesDeserializer.registerCustomKind(
"$GROUP/$API_VERSION",
BENCHMARK_SINGULAR,
BenchmarkCRD::class.java
)
val executionCRDClient: MixedOperation<
ExecutionCRD,
BenchmarkExecutionList,
Resource<ExecutionCRD>> = client.customResources(
ExecutionCRD::class.java,
BenchmarkExecutionList::class.java
)
val benchmarkCRDClient = client.customResources(
BenchmarkCRD::class.java,
KubernetesBenchmarkList::class.java
)
val appResource = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
this.controller =
TheodoliteController(
namespace = client.namespace,
path = appResource,
benchmarkCRDClient = benchmarkCRDClient,
executionCRDClient = executionCRDClient,
executionStateHandler = executionStateHandler
)
}
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ import io.quarkus.test.junit.QuarkusTest
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.KubernetesBenchmark
......@@ -30,7 +31,10 @@ class ControllerTest {
@BeforeEach
fun setUp() {
server.before()
this.controller = ControllerDummy(server.client).getController()
this.controller = TheodoliteOperator().getController(
client = server.client,
executionStateHandler = ExecutionStateHandler(server.client)
)
// benchmark
val benchmark1 = BenchmarkCRDummy(name = "Test-Benchmark")
......@@ -66,6 +70,38 @@ class ControllerTest {
server.after()
}
@Test
@DisplayName("Check namespaced property of benchmarkCRDClient")
fun testBenchmarkClientNamespaced(){
val method = controller
.javaClass
.getDeclaredMethod("getBenchmarks")
method.isAccessible = true
method.invoke(controller)
assert(server
.lastRequest
.toString()
.contains("namespaces")
)
}
@Test
@DisplayName("Check namespaced property of executionCRDClient")
fun testExecutionClientNamespaced(){
val method = controller
.javaClass
.getDeclaredMethod("getNextExecution")
method.isAccessible = true
method.invoke(controller)
assert(server
.lastRequest
.toString()
.contains("namespaces")
)
}
@Test
fun getBenchmarksTest() {
val method = controller
......
......@@ -11,8 +11,6 @@ import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import theodolite.k8s.K8sManager
import theodolite.k8s.K8sResourceLoader
import theodolite.model.crd.BenchmarkExecutionList
import theodolite.model.crd.ExecutionCRD
import theodolite.model.crd.States
import java.lang.Thread.sleep
......@@ -30,34 +28,27 @@ class ExecutionEventHandlerTest {
lateinit var executionVersion2: KubernetesResource
lateinit var stateHandler: ExecutionStateHandler
lateinit var manager: K8sManager
lateinit var controller: TheodoliteController
@BeforeEach
fun setUp() {
server.before()
val controllerDummy = ControllerDummy(server.client)
this.factory = server.client.informers()
val informerExecution = factory
.sharedIndexInformerForCustomResource(
ExecutionCRD::class.java,
BenchmarkExecutionList::class.java,
RESYNC_PERIOD
)
informerExecution.addEventHandler(
ExecutionHandler(
controller = controllerDummy.getController(),
stateHandler = controllerDummy.executionStateHandler
)
val operator = TheodoliteOperator()
this.controller = operator.getController(
client = server.client,
executionStateHandler = ExecutionStateHandler(client = server.client)
)
this.factory = operator.getExecutionEventHandler(server.client)
this.stateHandler = TheodoliteOperator().getExecutionStateHandler(client = server.client)
this.executionVersion1 = K8sResourceLoader(server.client)
.loadK8sResource("Execution", testResourcePath + "test-execution.yaml")
this.executionVersion2 = K8sResourceLoader(server.client)
.loadK8sResource("Execution", testResourcePath + "test-execution-update.yaml")
this.stateHandler = ControllerDummy(server.client).executionStateHandler
this.stateHandler = operator.getExecutionStateHandler(server.client)
this.manager = K8sManager((server.client))
}
......@@ -68,6 +59,20 @@ class ExecutionEventHandlerTest {
factory.stopAllRegisteredInformers()
}
@Test
@DisplayName("Check namespaced property of informers")
fun testNamespaced() {
manager.deploy(executionVersion1)
factory.startAllRegisteredInformers()
server.lastRequest
// the second request must be namespaced (this is the first `GET` request)
assert(server
.lastRequest
.toString()
.contains("namespaces")
)
}
@Test
@DisplayName("Test onAdd method for executions without execution state")
fun testWithoutState() {
......
......@@ -7,7 +7,6 @@ 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
......@@ -16,13 +15,6 @@ 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() {
......@@ -38,6 +30,18 @@ class StateHandlerTest {
server.after()
}
@Test
@DisplayName("check if Statehandler is namespaced")
fun namespacedTest() {
val handler = ExecutionStateHandler(client = server.client)
handler.getExecutionState("example-execution")
assert(server
.lastRequest
.toString()
.contains("namespaces")
)
}
@Test
@DisplayName("Test empty execution state")
fun executionWithoutExecutionStatusTest(){
......
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