From 40ef84a8562f7c1217c9742e255b455bec665e1a Mon Sep 17 00:00:00 2001
From: Marcel Becker <stu117960@mail.uni-kiel.de>
Date: Tue, 15 Mar 2022 13:51:02 +0100
Subject: [PATCH] Fixed Problems with KubernetesExecutionRunner

---
 .../rocks/theodolite/kubernetes/Main.kt       |  9 ++-
 .../rocks/theodolite/kubernetes/Shutdown.kt   |  7 +-
 .../execution/ExperimentRunnerImpl.kt         |  3 +-
 .../execution/KubernetesExecutionRunner.kt    | 10 +--
 .../execution/TheodoliteExecutor.kt           |  2 +-
 .../kubernetes/model/KubernetesBenchmark.kt   |  9 ---
 .../operator/BenchmarkStateChecker.kt         | 25 ++++---
 .../kubernetes/operator/ClusterSetup.kt       |  2 +-
 .../kubernetes/operator/EventCreator.kt       |  8 +--
 .../operator/TheodoliteController.kt          | 26 ++++++--
 .../kubernetes/operator/TheodoliteOperator.kt | 65 +++++++++----------
 .../standalone/TheodoliteStandalone.kt        |  7 +-
 .../theodolite/benchmark/ActionCommandTest.kt |  7 +-
 .../operator/BenchmarkStateCheckerTest.kt     | 14 ++--
 .../execution/operator/ControllerTest.kt      |  7 +-
 15 files changed, 105 insertions(+), 96 deletions(-)

diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Main.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Main.kt
index a8994efa4..7a21b580a 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Main.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Main.kt
@@ -1,5 +1,7 @@
 package rocks.theodolite.kubernetes
 
+import io.fabric8.kubernetes.client.DefaultKubernetesClient
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
 import io.quarkus.runtime.annotations.QuarkusMain
 import mu.KotlinLogging
 import rocks.theodolite.kubernetes.execution.ExecutionModes
@@ -19,9 +21,12 @@ object Main {
         val mode = Configuration.EXECUTION_MODE
         logger.info { "Start Theodolite with mode $mode" }
 
+        val namespace = Configuration.NAMESPACE
+        val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
+
         when (mode.lowercase()) {
-            ExecutionModes.STANDALONE.value -> TheodoliteStandalone().start()
-            ExecutionModes.OPERATOR.value -> TheodoliteOperator().start()
+            ExecutionModes.STANDALONE.value -> TheodoliteStandalone(client).start()
+            ExecutionModes.OPERATOR.value -> TheodoliteOperator(client).start()
             else -> {
                 logger.error { "MODE $mode not found" }
                 exitProcess(1)
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Shutdown.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Shutdown.kt
index 28b57ac0c..ce828e2df 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Shutdown.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/Shutdown.kt
@@ -1,5 +1,6 @@
 package rocks.theodolite.kubernetes
 
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
 import mu.KotlinLogging
 import rocks.theodolite.kubernetes.execution.KubernetesExecutionRunner
 import rocks.theodolite.kubernetes.model.BenchmarkExecution
@@ -13,7 +14,9 @@ private val logger = KotlinLogging.logger {}
  * @property benchmarkExecution
  * @property benchmark
  */
-class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val benchmark: KubernetesBenchmark) {
+class Shutdown(private val benchmarkExecution: BenchmarkExecution,
+               private val benchmark: KubernetesBenchmark,
+               private val client: NamespacedKubernetesClient) {
 
     /**
      * Run
@@ -21,7 +24,7 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b
      */
     fun run() {
         // Build Configuration to teardown
-        val kubernetesExecutionRunner = KubernetesExecutionRunner(benchmark)
+        val kubernetesExecutionRunner = KubernetesExecutionRunner(benchmark, this.client)
         try {
             logger.info { "Received shutdown signal -> Shutting down" }
             val deployment =
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/ExperimentRunnerImpl.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/ExperimentRunnerImpl.kt
index c5b5de129..a33e9518f 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/ExperimentRunnerImpl.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/ExperimentRunnerImpl.kt
@@ -1,5 +1,6 @@
 package rocks.theodolite.kubernetes.execution
 
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
 import io.quarkus.runtime.annotations.RegisterForReflection
 import mu.KotlinLogging
 import rocks.theodolite.core.ExperimentRunner
@@ -30,7 +31,7 @@ class ExperimentRunnerImpl(
         private val afterTeardownDelay: Long,
         private val executionName: String,
         private val loadPatcherDefinitions: List<PatcherDefinition>,
-        private val resourcePatcherDefinitions: List<PatcherDefinition>
+        private val resourcePatcherDefinitions: List<PatcherDefinition>,
 ) : ExperimentRunner(
         results
 ) {
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/KubernetesExecutionRunner.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/KubernetesExecutionRunner.kt
index f72940751..493aabdb9 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/KubernetesExecutionRunner.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/KubernetesExecutionRunner.kt
@@ -17,12 +17,8 @@ private val logger = KotlinLogging.logger {}
 
 private var DEFAULT_NAMESPACE = "default"
 
-class KubernetesExecutionRunner(val kubernetesBenchmark: KubernetesBenchmark) : Benchmark {
-
-    private var namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
-
-    @Transient
-    private var client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
+class KubernetesExecutionRunner(val kubernetesBenchmark: KubernetesBenchmark,
+                                private var client: NamespacedKubernetesClient) : Benchmark {
 
     /**
      * Loads [KubernetesResource]s.
@@ -68,7 +64,7 @@ class KubernetesExecutionRunner(val kubernetesBenchmark: KubernetesBenchmark) :
             loadGenerationDelay: Long,
             afterTeardownDelay: Long
     ): BenchmarkDeployment {
-        logger.info { "Using ${this.namespace} as namespace." }
+        logger.info { "Using ${this.client.namespace} as namespace." }
 
         val appResources = loadKubernetesResources(kubernetesBenchmark.sut.resources)
         val loadGenResources = loadKubernetesResources(kubernetesBenchmark.loadGenerator.resources)
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/TheodoliteExecutor.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/TheodoliteExecutor.kt
index 6178d803c..1dc3d4d52 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/TheodoliteExecutor.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/execution/TheodoliteExecutor.kt
@@ -68,7 +68,7 @@ class TheodoliteExecutor(
                 results = results,
                 executionDuration = executionDuration,
                 configurationOverrides = benchmarkExecution.configOverrides,
-                slos = kubernetesBenchmark.slos,
+                slos = slos,
                 repetitions = benchmarkExecution.execution.repetitions,
                 executionId = benchmarkExecution.executionId,
                 loadGenerationDelay = benchmarkExecution.execution.loadGenerationDelay,
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/model/KubernetesBenchmark.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/model/KubernetesBenchmark.kt
index d32a42b7b..9498374e1 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/model/KubernetesBenchmark.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/model/KubernetesBenchmark.kt
@@ -36,7 +36,6 @@ class KubernetesBenchmark : KubernetesResource {
     lateinit var infrastructure: Resources
     lateinit var sut: Resources
     lateinit var loadGenerator: Resources
-    //TODO: maybe add identifier and in BenchmarkCRD maybe manage them
 
     /**
      * The TypeName encapsulates a list of [PatcherDefinition] along with a typeName that specifies for what the [PatcherDefinition] should be used.
@@ -74,12 +73,4 @@ class KubernetesBenchmark : KubernetesResource {
         lateinit var beforeActions: List<Action>
         lateinit var afterActions: List<Action>
     }
-
-/*    fun getClient() : NamespacedKubernetesClient {
-        return this.client
-    }
-
-    fun getNamespace() : String {
-        return this.namespace
-    }*/
 }
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateChecker.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateChecker.kt
index b91201317..5c9359b7a 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateChecker.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/BenchmarkStateChecker.kt
@@ -1,5 +1,6 @@
 package rocks.theodolite.kubernetes.operator
 
+import io.fabric8.kubernetes.api.model.KubernetesResource
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import io.fabric8.kubernetes.api.model.apps.StatefulSet
 import io.fabric8.kubernetes.client.NamespacedKubernetesClient
@@ -10,6 +11,7 @@ import rocks.theodolite.kubernetes.benchmark.ActionSelector
 import rocks.theodolite.kubernetes.model.KubernetesBenchmark
 import rocks.theodolite.kubernetes.resourceSet.ResourceSets
 import rocks.theodolite.kubernetes.execution.KubernetesExecutionRunner
+import rocks.theodolite.kubernetes.k8s.resourceLoader.K8sResourceLoader
 import rocks.theodolite.kubernetes.model.crd.BenchmarkCRD
 import rocks.theodolite.kubernetes.model.crd.BenchmarkState
 import rocks.theodolite.kubernetes.model.crd.KubernetesBenchmarkList
@@ -18,7 +20,6 @@ class BenchmarkStateChecker(
         private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>,
         private val benchmarkStateHandler: BenchmarkStateHandler,
         private val client: NamespacedKubernetesClient,
-        //private val kubernetesExecutionRunnerList: List<KubernetesExecutionRunner>
 
 ) {
 
@@ -54,9 +55,9 @@ class BenchmarkStateChecker(
      * @param benchmark The benchmark to check
      * @return [BenchmarkStates.READY] iff all resource could be loaded and all actions could be executed, [BenchmarkStates.PENDING] else
      */
-    private fun checkState(kubernetesExecutionRunner: KubernetesExecutionRunner): BenchmarkState {
-        return if (checkActionCommands(kubernetesExecutionRunner.kubernetesBenchmark) == BenchmarkState.READY
-            && checkResources(kubernetesExecutionRunner) == BenchmarkState.READY
+    private fun checkState(benchmark: KubernetesBenchmark): BenchmarkState {
+        return if (checkActionCommands(benchmark) == BenchmarkState.READY
+            && checkResources(benchmark) == BenchmarkState.READY
         ) {
             BenchmarkState.READY
         } else {
@@ -175,13 +176,12 @@ class BenchmarkStateChecker(
      * @param benchmark The benchmark to check
      * @return The state of this benchmark. [BenchmarkState.READY] if all resources could be loaded, else [BenchmarkState.PENDING]
      */
-    fun checkResources(kubernetesExecutionRunner: KubernetesExecutionRunner): BenchmarkState {
+    fun checkResources(benchmark: KubernetesBenchmark): BenchmarkState {
         return try {
-            val benchmark = kubernetesExecutionRunner.kubernetesBenchmark
             val appResources =
-                    kubernetesExecutionRunner.loadKubernetesResources(resourceSet = benchmark.sut.resources)
+                    loadKubernetesResources(resourceSet = benchmark.sut.resources)
             val loadGenResources =
-                    kubernetesExecutionRunner.loadKubernetesResources(resourceSet = benchmark.loadGenerator.resources)
+                    loadKubernetesResources(resourceSet = benchmark.loadGenerator.resources)
             if (appResources.isNotEmpty() && loadGenResources.isNotEmpty()) {
                 BenchmarkState.READY
             } else {
@@ -191,6 +191,15 @@ class BenchmarkStateChecker(
             BenchmarkState.PENDING
         }
     }
+
+    /**
+     * Loads [KubernetesResource]s.
+     * It first loads them via the [YamlParserFromFile] to check for their concrete type and afterwards initializes them using
+     * the [K8sResourceLoader]
+     */
+    private fun loadKubernetesResources(resourceSet: List<ResourceSets>): Collection<Pair<String, KubernetesResource>> {
+        return resourceSet.flatMap { it.loadResourceSet(this.client) }
+    }
 }
 
 private fun <K, V> MutableMap<K, V>.containsMatchLabels(matchLabels: MutableMap<V, V>): Boolean {
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ClusterSetup.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ClusterSetup.kt
index 34c14114e..db95659f0 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ClusterSetup.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/ClusterSetup.kt
@@ -50,7 +50,7 @@ class ClusterSetup(
                 if (benchmark != null) {
                     execution.spec.name = execution.metadata.name
                     benchmark.spec.name = benchmark.metadata.name
-                    Shutdown(execution.spec, benchmark.spec).run()
+                    Shutdown(execution.spec, benchmark.spec, client).run()
                 } else {
                     throw IllegalStateException("Execution with state ${ExecutionState.RUNNING.value} was found, but no corresponding benchmark. " +
                             "Could not initialize cluster.")
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/EventCreator.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/EventCreator.kt
index b1a8dc8c3..cb23f8791 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/EventCreator.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/EventCreator.kt
@@ -13,7 +13,7 @@ import kotlin.NoSuchElementException
 private val logger = KotlinLogging.logger {}
 
 class EventCreator {
-    val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(Configuration.NAMESPACE)
+    private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(Configuration.NAMESPACE)
 
     fun createEvent(executionName: String, type: String, message: String, reason: String) {
         val uuid = UUID.randomUUID().toString()
@@ -34,15 +34,15 @@ class EventCreator {
             event.source = source
 
             event.involvedObject = objectRef
-            client.v1().events().inNamespace(Configuration.NAMESPACE).createOrReplace(event)
+            this.client.v1().events().inNamespace(Configuration.NAMESPACE).createOrReplace(event)
         } catch (e: NoSuchElementException) {
                 logger.warn {"Could not create event: type: $type, message: $message, reason: $reason, no corresponding execution found."}
         }
     }
 
     private fun buildObjectReference(executionName: String): ObjectReference {
-        val exec = TheodoliteOperator()
-            .getExecutionClient(client = client)
+        val exec = TheodoliteOperator(this.client)
+            .getExecutionClient()
             .list()
             .items
             .first{it.metadata.name == executionName}
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteController.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteController.kt
index d3171fec8..8fcb42ca4 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteController.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteController.kt
@@ -1,5 +1,7 @@
 package rocks.theodolite.kubernetes.operator
 
+import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
 import io.fabric8.kubernetes.client.dsl.MixedOperation
 import io.fabric8.kubernetes.client.dsl.Resource
 import mu.KotlinLogging
@@ -10,9 +12,11 @@ import rocks.theodolite.kubernetes.model.crd.KubernetesBenchmarkList
 import rocks.theodolite.kubernetes.model.KubernetesBenchmark
 import rocks.theodolite.kubernetes.execution.KubernetesExecutionRunner
 import rocks.theodolite.kubernetes.execution.TheodoliteExecutor
+import rocks.theodolite.kubernetes.k8s.resourceLoader.K8sResourceLoader
 import rocks.theodolite.kubernetes.model.crd.*
 import rocks.theodolite.kubernetes.patcher.ConfigOverrideModifier
 import rocks.theodolite.kubernetes.model.crd.ExecutionStateComparator
+import rocks.theodolite.kubernetes.resourceSet.ResourceSets
 import java.lang.Thread.sleep
 
 private val logger = KotlinLogging.logger {}
@@ -29,10 +33,12 @@ const val CREATED_BY_LABEL_VALUE = "rocks/theodolite"
  */
 
 class TheodoliteController(
+        private val client: NamespacedKubernetesClient,
         private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, Resource<ExecutionCRD>>,
         private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>,
         private val executionStateHandler: ExecutionStateHandler,
-        private val benchmarkStateChecker: BenchmarkStateChecker
+        private val benchmarkStateChecker: BenchmarkStateChecker,
+
 ) {
     lateinit var executor: TheodoliteExecutor
 
@@ -71,11 +77,10 @@ class TheodoliteController(
      */
     private fun runExecution(execution: BenchmarkExecution, benchmark: KubernetesBenchmark) {
         try {
-            val kubernetesExecutionRunner = KubernetesExecutionRunner(benchmark)
             val modifier = ConfigOverrideModifier(
-                execution = execution,
-                resources = kubernetesExecutionRunner.loadKubernetesResources(benchmark.sut.resources).map { it.first }
-                        + kubernetesExecutionRunner.loadKubernetesResources(benchmark.loadGenerator.resources).map { it.first }
+                    execution = execution,
+                    resources = loadKubernetesResources(benchmark.sut.resources).map { it.first }
+                            + loadKubernetesResources(benchmark.loadGenerator.resources).map { it.first }
             )
             modifier.setAdditionalLabels(
                 labelValue = execution.name,
@@ -93,7 +98,7 @@ class TheodoliteController(
             executionStateHandler.setExecutionState(execution.name, ExecutionState.RUNNING)
             executionStateHandler.startDurationStateTimer(execution.name)
 
-            executor = TheodoliteExecutor(execution, kubernetesExecutionRunner)
+            executor = TheodoliteExecutor(execution, KubernetesExecutionRunner(benchmark, this.client))
             executor.setupAndRunExecution()
             when (executionStateHandler.getExecutionState(execution.name)) {
                 ExecutionState.RESTART -> runExecution(execution, benchmark)
@@ -176,4 +181,13 @@ class TheodoliteController(
         if (!::executor.isInitialized) return false
         return this.executor.getExecution().name == executionName
     }
+
+    /**
+     * Loads [KubernetesResource]s.
+     * It first loads them via the [YamlParserFromFile] to check for their concrete type and afterwards initializes them using
+     * the [K8sResourceLoader]
+     */
+    private fun loadKubernetesResources(resourceSet: List<ResourceSets>): Collection<Pair<String, KubernetesResource>> {
+        return resourceSet.flatMap { it.loadResourceSet(this.client) }
+    }
 }
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt
index 3a38844a7..83420b55a 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/operator/TheodoliteOperator.kt
@@ -1,6 +1,5 @@
 package rocks.theodolite.kubernetes.operator
 
-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
@@ -14,7 +13,6 @@ import rocks.theodolite.kubernetes.model.crd.KubernetesBenchmarkList
 import rocks.theodolite.kubernetes.util.Configuration
 
 
-private const val DEFAULT_NAMESPACE = "default"
 private const val EXECUTION_SINGULAR = "execution"
 private const val BENCHMARK_SINGULAR = "benchmark"
 private const val API_VERSION = "v1"
@@ -27,10 +25,7 @@ private val logger = KotlinLogging.logger {}
  *
  * **See Also:** [Kubernetes Operator Pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)
  */
-class TheodoliteOperator {
-    private val namespace = Configuration.NAMESPACE
-
-    private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
+class TheodoliteOperator(private val client: NamespacedKubernetesClient) {
     private lateinit var controller: TheodoliteController
     private lateinit var executionStateHandler: ExecutionStateHandler
     private lateinit var benchmarkStateHandler: BenchmarkStateHandler
@@ -39,7 +34,7 @@ class TheodoliteOperator {
 
     fun start() {
         LeaderElector(
-            client = client,
+            client = this.client,
             name = Configuration.COMPONENT_NAME
         )
             .getLeadership(::startOperator)
@@ -49,8 +44,8 @@ class TheodoliteOperator {
      * Start the operator.
      */
     private fun startOperator() {
-        logger.info { "Using $namespace as namespace." }
-        client.use {
+        logger.info { "Using ${this.client.namespace} as namespace." }
+        this.client.use {
             KubernetesDeserializer.registerCustomKind(
                 "$GROUP/$API_VERSION",
                 EXECUTION_SINGULAR,
@@ -64,28 +59,26 @@ class TheodoliteOperator {
             )
 
             ClusterSetup(
-                executionCRDClient = getExecutionClient(client),
-                benchmarkCRDClient = getBenchmarkClient(client),
-                client = client
+                executionCRDClient = getExecutionClient(),
+                benchmarkCRDClient = getBenchmarkClient(),
+                client = this.client
             ).clearClusterState()
 
             controller = getController(
-                client = client,
-                executionStateHandler = getExecutionStateHandler(client = client),
-                benchmarkStateChecker = getBenchmarkStateChecker(client = client)
+                executionStateHandler = getExecutionStateHandler(),
+                benchmarkStateChecker = getBenchmarkStateChecker()
 
             )
-            getExecutionEventHandler(controller, client).startAllRegisteredInformers()
+            getExecutionEventHandler(controller).startAllRegisteredInformers()
             controller.run()
         }
     }
 
-    fun getExecutionEventHandler(
+    private fun getExecutionEventHandler(
             controller: TheodoliteController,
-            client: NamespacedKubernetesClient
     ): SharedInformerFactory {
-        val factory = client.informers()
-            .inNamespace(client.namespace)
+        val factory = this.client.informers()
+            .inNamespace(this.client.namespace)
 
         factory.sharedIndexInformerForCustomResource(
             ExecutionCRD::class.java,
@@ -93,46 +86,46 @@ class TheodoliteOperator {
         ).addEventHandler(
             ExecutionEventHandler(
                 controller = controller,
-                stateHandler = ExecutionStateHandler(client)
+                stateHandler = ExecutionStateHandler(this.client)
             )
         )
         return factory
     }
 
-    fun getExecutionStateHandler(client: NamespacedKubernetesClient): ExecutionStateHandler {
+    fun getExecutionStateHandler(): ExecutionStateHandler {
         if (!::executionStateHandler.isInitialized) {
-            this.executionStateHandler = ExecutionStateHandler(client = client)
+            this.executionStateHandler = ExecutionStateHandler(client = this.client)
         }
         return executionStateHandler
     }
 
-    fun getBenchmarkStateHandler(client: NamespacedKubernetesClient) : BenchmarkStateHandler {
+    fun getBenchmarkStateHandler() : BenchmarkStateHandler {
         if (!::benchmarkStateHandler.isInitialized) {
-            this.benchmarkStateHandler = BenchmarkStateHandler(client = client)
+            this.benchmarkStateHandler = BenchmarkStateHandler(client = this.client)
         }
         return benchmarkStateHandler
     }
 
-    fun getBenchmarkStateChecker(client: NamespacedKubernetesClient) : BenchmarkStateChecker {
+    fun getBenchmarkStateChecker() : BenchmarkStateChecker {
         if (!::benchmarkStateChecker.isInitialized) {
             this.benchmarkStateChecker = BenchmarkStateChecker(
-                client = client,
-                benchmarkStateHandler = getBenchmarkStateHandler(client = client),
-                benchmarkCRDClient = getBenchmarkClient(client = client))
+                client = this.client,
+                benchmarkStateHandler = getBenchmarkStateHandler(),
+                benchmarkCRDClient = getBenchmarkClient())
         }
         return benchmarkStateChecker
     }
 
 
     fun getController(
-            client: NamespacedKubernetesClient,
             executionStateHandler: ExecutionStateHandler,
             benchmarkStateChecker: BenchmarkStateChecker
     ): TheodoliteController {
         if (!::controller.isInitialized) {
             this.controller = TheodoliteController(
-                benchmarkCRDClient = getBenchmarkClient(client),
-                executionCRDClient = getExecutionClient(client),
+                client = this.client,
+                benchmarkCRDClient = getBenchmarkClient(),
+                executionCRDClient = getExecutionClient(),
                 executionStateHandler = executionStateHandler,
                 benchmarkStateChecker = benchmarkStateChecker
             )
@@ -140,21 +133,21 @@ class TheodoliteOperator {
         return this.controller
     }
 
-    fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation<
+    fun getExecutionClient(): MixedOperation<
             ExecutionCRD,
             BenchmarkExecutionList,
             Resource<ExecutionCRD>> {
-        return client.customResources(
+        return this.client.customResources(
             ExecutionCRD::class.java,
             BenchmarkExecutionList::class.java
         )
     }
 
-    fun getBenchmarkClient(client: NamespacedKubernetesClient): MixedOperation<
+    fun getBenchmarkClient(): MixedOperation<
             BenchmarkCRD,
             KubernetesBenchmarkList,
             Resource<BenchmarkCRD>> {
-        return client.customResources(
+        return this.client.customResources(
             BenchmarkCRD::class.java,
             KubernetesBenchmarkList::class.java
         )
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/standalone/TheodoliteStandalone.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/standalone/TheodoliteStandalone.kt
index c6a257ea7..95092edf3 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/standalone/TheodoliteStandalone.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/standalone/TheodoliteStandalone.kt
@@ -1,5 +1,6 @@
 package rocks.theodolite.kubernetes.standalone
 
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
 import mu.KotlinLogging
 import rocks.theodolite.kubernetes.model.BenchmarkExecution
 import rocks.theodolite.kubernetes.model.KubernetesBenchmark
@@ -31,7 +32,7 @@ private val logger = KotlinLogging.logger {}
  *
  * @constructor Create empty Theodolite yaml executor
  */
-class TheodoliteStandalone {
+class TheodoliteStandalone (private val client: NamespacedKubernetesClient) {
     private val parser = YamlParserFromFile()
 
     fun start() {
@@ -52,11 +53,11 @@ class TheodoliteStandalone {
 
         // Add shutdown hook
         // Use thread{} with start = false, else the thread will start right away
-        val shutdown = thread(start = false) { Shutdown(benchmarkExecution, benchmark).run() }
+        val shutdown = thread(start = false) { Shutdown(benchmarkExecution, benchmark, client).run() }
         Runtime.getRuntime().addShutdownHook(shutdown)
 
         try {
-            TheodoliteExecutor(benchmarkExecution, KubernetesExecutionRunner(benchmark)).setupAndRunExecution()
+            TheodoliteExecutor(benchmarkExecution, KubernetesExecutionRunner(benchmark, client)).setupAndRunExecution()
         } catch (e: EvaluationFailedException) {
             logger.error { "Evaluation failed with error: ${e.message}" }
         }catch (e: ExecutionFailedException) {
diff --git a/theodolite/src/test/kotlin/theodolite/benchmark/ActionCommandTest.kt b/theodolite/src/test/kotlin/theodolite/benchmark/ActionCommandTest.kt
index ef80526b3..e88aeb1e3 100644
--- a/theodolite/src/test/kotlin/theodolite/benchmark/ActionCommandTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/benchmark/ActionCommandTest.kt
@@ -22,11 +22,10 @@ class ActionCommandTest {
     @BeforeEach
     fun setUp() {
         server.before()
-        val operator = TheodoliteOperator()
+        val operator = TheodoliteOperator(server.client)
         this.controller = operator.getController(
-            client = server.client,
-            executionStateHandler = operator.getExecutionStateHandler(client = server.client),
-            benchmarkStateChecker = operator.getBenchmarkStateChecker(client = server.client)
+            executionStateHandler = operator.getExecutionStateHandler(),
+            benchmarkStateChecker = operator.getBenchmarkStateChecker()
         )
 
         val pod: Pod = PodBuilder().withNewMetadata()
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkStateCheckerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkStateCheckerTest.kt
index fcbc577fc..53d8d4b68 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkStateCheckerTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkStateCheckerTest.kt
@@ -32,17 +32,17 @@ internal class BenchmarkStateCheckerTest {
     fun setUp() {
         server.before()
         serverCrud.before()
-        val operator = TheodoliteOperator()
+        val operator = TheodoliteOperator(serverCrud.client)
         checker = BenchmarkStateChecker(
             client = server.client,
-            benchmarkCRDClient = operator.getBenchmarkClient(server.client),
-            benchmarkStateHandler = operator.getBenchmarkStateHandler(server.client)
+            benchmarkCRDClient = operator.getBenchmarkClient(),
+            benchmarkStateHandler = operator.getBenchmarkStateHandler()
         )
 
         checkerCrud = BenchmarkStateChecker(
             client = serverCrud.client,
-            benchmarkCRDClient = operator.getBenchmarkClient(serverCrud.client),
-            benchmarkStateHandler = operator.getBenchmarkStateHandler(serverCrud.client)
+            benchmarkCRDClient = operator.getBenchmarkClient(),
+            benchmarkStateHandler = operator.getBenchmarkStateHandler()
         )
 
         val pod: Pod = PodBuilder().withNewMetadata()
@@ -172,8 +172,6 @@ internal class BenchmarkStateCheckerTest {
             name = "test-benchmark"
         )
         val benchmark = benchmarkCR.getCR().spec
-        val kubernetesExecutionRunner = KubernetesExecutionRunner(benchmark)
-        kubernetesExecutionRunner.setClient(serverCrud.client)
 
         val resourceSet = KubernetesBenchmark.Resources()
         resourceSet.resources = listOf(createAndDeployConfigmapResourceSet())
@@ -181,6 +179,6 @@ internal class BenchmarkStateCheckerTest {
         benchmark.loadGenerator = resourceSet
         benchmark.sut = resourceSet
 
-        assertEquals(BenchmarkState.READY,checkerCrud.checkResources(kubernetesExecutionRunner))
+        assertEquals(BenchmarkState.READY,checkerCrud.checkResources(benchmark))
     }
 }
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt
index 19cc0cd03..144bf2717 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt
@@ -35,11 +35,10 @@ class ControllerTest {
     @BeforeEach
     fun setUp() {
         server.before()
-        val operator = TheodoliteOperator()
+        val operator = TheodoliteOperator(server.client)
         this.controller = operator.getController(
-            client = server.client,
-            executionStateHandler = operator.getExecutionStateHandler(client = server.client),
-            benchmarkStateChecker = operator.getBenchmarkStateChecker(client = server.client)
+            executionStateHandler = operator.getExecutionStateHandler(),
+            benchmarkStateChecker = operator.getBenchmarkStateChecker()
         )
 
         // benchmark
-- 
GitLab