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 package theodolite.execution.operator
import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.MixedOperation import io.fabric8.kubernetes.client.dsl.MixedOperation
import io.fabric8.kubernetes.client.dsl.Resource import io.fabric8.kubernetes.client.dsl.Resource
import mu.KotlinLogging import mu.KotlinLogging
...@@ -17,15 +16,12 @@ private val logger = KotlinLogging.logger {} ...@@ -17,15 +16,12 @@ private val logger = KotlinLogging.logger {}
/** /**
* The controller implementation for Theodolite. * The controller implementation for Theodolite.
* *
* @see NamespacedKubernetesClient
* @see CustomResourceDefinitionContext
* @see BenchmarkExecution * @see BenchmarkExecution
* @see KubernetesBenchmark * @see KubernetesBenchmark
* @see ConcurrentLinkedDeque * @see ConcurrentLinkedDeque
*/ */
class TheodoliteController( class TheodoliteController(
private val namespace: String,
val path: String, val path: String,
private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, Resource<ExecutionCRD>>, private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, Resource<ExecutionCRD>>,
private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>, private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>,
...@@ -116,11 +112,10 @@ class TheodoliteController( ...@@ -116,11 +112,10 @@ class TheodoliteController(
*/ */
private fun getBenchmarks(): List<KubernetesBenchmark> { private fun getBenchmarks(): List<KubernetesBenchmark> {
return this.benchmarkCRDClient return this.benchmarkCRDClient
.inNamespace(namespace)
.list() .list()
.items .items
.map { it.spec.name = it.metadata.name; it } .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 } .map { it.spec }
} }
...@@ -140,7 +135,6 @@ class TheodoliteController( ...@@ -140,7 +135,6 @@ class TheodoliteController(
.map { it.name } .map { it.name }
return executionCRDClient return executionCRDClient
.inNamespace(namespace)
.list() .list()
.items .items
.asSequence() .asSequence()
......
...@@ -4,6 +4,7 @@ import io.fabric8.kubernetes.client.DefaultKubernetesClient ...@@ -4,6 +4,7 @@ import io.fabric8.kubernetes.client.DefaultKubernetesClient
import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.MixedOperation import io.fabric8.kubernetes.client.dsl.MixedOperation
import io.fabric8.kubernetes.client.dsl.Resource import io.fabric8.kubernetes.client.dsl.Resource
import io.fabric8.kubernetes.client.informers.SharedInformerFactory
import io.fabric8.kubernetes.internal.KubernetesDeserializer import io.fabric8.kubernetes.internal.KubernetesDeserializer
import mu.KotlinLogging import mu.KotlinLogging
import theodolite.model.crd.BenchmarkCRD import theodolite.model.crd.BenchmarkCRD
...@@ -27,7 +28,11 @@ private val logger = KotlinLogging.logger {} ...@@ -27,7 +28,11 @@ private val logger = KotlinLogging.logger {}
*/ */
class TheodoliteOperator { class TheodoliteOperator {
private val namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE 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() { fun start() {
...@@ -41,7 +46,7 @@ class TheodoliteOperator { ...@@ -41,7 +46,7 @@ class TheodoliteOperator {
/** /**
* Start the operator. * Start the operator.
*/ */
private fun startOperator() { private fun startOperator() {
logger.info { "Using $namespace as namespace." } logger.info { "Using $namespace as namespace." }
client.use { client.use {
KubernetesDeserializer.registerCustomKind( KubernetesDeserializer.registerCustomKind(
...@@ -56,56 +61,75 @@ class TheodoliteOperator { ...@@ -56,56 +61,75 @@ class TheodoliteOperator {
BenchmarkCRD::class.java BenchmarkCRD::class.java
) )
val executionCRDClient: MixedOperation< ClusterSetup(
ExecutionCRD, executionCRDClient = getExecutionClient(client),
BenchmarkExecutionList, benchmarkCRDClient = getBenchmarkClient(client),
Resource<ExecutionCRD>> client = client
= client.customResources( ).clearClusterState()
ExecutionCRD::class.java,
BenchmarkExecutionList::class.java
)
val benchmarkCRDClient: MixedOperation< getController(
BenchmarkCRD, client = client,
KubernetesBenchmarkList, executionStateHandler = getExecutionStateHandler(client = client)
Resource<BenchmarkCRD>> ).run()
= client.customResources( getExecutionEventHandler(client).startAllRegisteredInformers()
BenchmarkCRD::class.java, }
KubernetesBenchmarkList::class.java }
)
val executionStateHandler = ExecutionStateHandler( fun getExecutionEventHandler(client: NamespacedKubernetesClient): SharedInformerFactory {
client = client) val factory = client.informers()
.inNamespace(client.namespace)
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
)
informerExecution.addEventHandler(ExecutionHandler( factory.sharedIndexInformerForCustomResource(
ExecutionCRD::class.java,
RESYNC_PERIOD
).addEventHandler(
ExecutionHandler(
controller = controller, controller = controller,
stateHandler = executionStateHandler)) stateHandler = ExecutionStateHandler(client)
)
ClusterSetup( )
executionCRDClient = executionCRDClient, return factory
benchmarkCRDClient = benchmarkCRDClient, }
client = client
).clearClusterState()
informerFactory.startAllRegisteredInformers() fun getExecutionStateHandler(client: NamespacedKubernetesClient): ExecutionStateHandler {
controller.run() 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 ...@@ -8,6 +8,7 @@ import io.quarkus.test.junit.QuarkusTest
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import theodolite.benchmark.BenchmarkExecution import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.KubernetesBenchmark import theodolite.benchmark.KubernetesBenchmark
...@@ -30,7 +31,10 @@ class ControllerTest { ...@@ -30,7 +31,10 @@ class ControllerTest {
@BeforeEach @BeforeEach
fun setUp() { fun setUp() {
server.before() server.before()
this.controller = ControllerDummy(server.client).getController() this.controller = TheodoliteOperator().getController(
client = server.client,
executionStateHandler = ExecutionStateHandler(server.client)
)
// benchmark // benchmark
val benchmark1 = BenchmarkCRDummy(name = "Test-Benchmark") val benchmark1 = BenchmarkCRDummy(name = "Test-Benchmark")
...@@ -66,6 +70,38 @@ class ControllerTest { ...@@ -66,6 +70,38 @@ class ControllerTest {
server.after() 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 @Test
fun getBenchmarksTest() { fun getBenchmarksTest() {
val method = controller val method = controller
......
...@@ -11,8 +11,6 @@ import org.junit.jupiter.api.DisplayName ...@@ -11,8 +11,6 @@ import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import theodolite.k8s.K8sManager import theodolite.k8s.K8sManager
import theodolite.k8s.K8sResourceLoader import theodolite.k8s.K8sResourceLoader
import theodolite.model.crd.BenchmarkExecutionList
import theodolite.model.crd.ExecutionCRD
import theodolite.model.crd.States import theodolite.model.crd.States
import java.lang.Thread.sleep import java.lang.Thread.sleep
...@@ -30,34 +28,27 @@ class ExecutionEventHandlerTest { ...@@ -30,34 +28,27 @@ class ExecutionEventHandlerTest {
lateinit var executionVersion2: KubernetesResource lateinit var executionVersion2: KubernetesResource
lateinit var stateHandler: ExecutionStateHandler lateinit var stateHandler: ExecutionStateHandler
lateinit var manager: K8sManager lateinit var manager: K8sManager
lateinit var controller: TheodoliteController
@BeforeEach @BeforeEach
fun setUp() { fun setUp() {
server.before() server.before()
val controllerDummy = ControllerDummy(server.client) val operator = TheodoliteOperator()
this.controller = operator.getController(
this.factory = server.client.informers() client = server.client,
val informerExecution = factory executionStateHandler = ExecutionStateHandler(client = server.client)
.sharedIndexInformerForCustomResource(
ExecutionCRD::class.java,
BenchmarkExecutionList::class.java,
RESYNC_PERIOD
)
informerExecution.addEventHandler(
ExecutionHandler(
controller = controllerDummy.getController(),
stateHandler = controllerDummy.executionStateHandler
)
) )
this.factory = operator.getExecutionEventHandler(server.client)
this.stateHandler = TheodoliteOperator().getExecutionStateHandler(client = server.client)
this.executionVersion1 = K8sResourceLoader(server.client) this.executionVersion1 = K8sResourceLoader(server.client)
.loadK8sResource("Execution", testResourcePath + "test-execution.yaml") .loadK8sResource("Execution", testResourcePath + "test-execution.yaml")
this.executionVersion2 = K8sResourceLoader(server.client) this.executionVersion2 = K8sResourceLoader(server.client)
.loadK8sResource("Execution", testResourcePath + "test-execution-update.yaml") .loadK8sResource("Execution", testResourcePath + "test-execution-update.yaml")
this.stateHandler = ControllerDummy(server.client).executionStateHandler this.stateHandler = operator.getExecutionStateHandler(server.client)
this.manager = K8sManager((server.client)) this.manager = K8sManager((server.client))
} }
...@@ -68,6 +59,20 @@ class ExecutionEventHandlerTest { ...@@ -68,6 +59,20 @@ class ExecutionEventHandlerTest {
factory.stopAllRegisteredInformers() 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 @Test
@DisplayName("Test onAdd method for executions without execution state") @DisplayName("Test onAdd method for executions without execution state")
fun testWithoutState() { fun testWithoutState() {
......
...@@ -7,7 +7,6 @@ import org.junit.jupiter.api.Assertions.assertTrue ...@@ -7,7 +7,6 @@ import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import theodolite.k8s.K8sContextFactory
import theodolite.k8s.K8sManager import theodolite.k8s.K8sManager
import theodolite.k8s.K8sResourceLoader import theodolite.k8s.K8sResourceLoader
import theodolite.model.crd.States import theodolite.model.crd.States
...@@ -16,13 +15,6 @@ import java.time.Duration ...@@ -16,13 +15,6 @@ import java.time.Duration
class StateHandlerTest { class StateHandlerTest {
private val testResourcePath = "./src/test/resources/k8s-resource-files/" private val testResourcePath = "./src/test/resources/k8s-resource-files/"
private val server = KubernetesServer(false, true) private val server = KubernetesServer(false, true)
private val context = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "theodolite.com",
plural = "executions"
)
@BeforeEach @BeforeEach
fun setUp() { fun setUp() {
...@@ -38,6 +30,18 @@ class StateHandlerTest { ...@@ -38,6 +30,18 @@ class StateHandlerTest {
server.after() 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 @Test
@DisplayName("Test empty execution state") @DisplayName("Test empty execution state")
fun executionWithoutExecutionStatusTest(){ 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