From 0968e10ba1961d9049b10d981d967f6bb45c784f Mon Sep 17 00:00:00 2001
From: "stu126940@mail.uni-kiel.de" <stu126940@mail.uni-kiel.de>
Date: Thu, 3 Jun 2021 18:50:51 +0200
Subject: [PATCH] change patcherDefinition in order to use a map for all
 configuration params

---
 .../operator/TheodoliteController.kt          |  2 +-
 .../theodolite/patcher/AbstractPatcher.kt     |  4 +-
 .../theodolite/patcher/EnvVarPatcher.kt       |  2 +-
 .../kotlin/theodolite/patcher/ImagePatcher.kt |  2 +-
 .../kotlin/theodolite/patcher/LabelPatcher.kt |  3 +-
 .../theodolite/patcher/NodeSelectorPatcher.kt |  2 +-
 ...NestedGroupsLoadGeneratorReplicaPatcher.kt | 13 ++---
 .../NumSensorsLoadGeneratorReplicaPatcher.kt  |  8 +--
 .../theodolite/patcher/PatcherFactory.kt      | 51 ++++++++++++++-----
 .../patcher/ResourceLimitPatcher.kt           |  2 +-
 .../patcher/ResourceRequestPatcher.kt         |  2 +-
 .../InvalidPatcherConfigurationException.kt   |  5 ++
 .../theodolite/util/PatcherDefinition.kt      | 28 +++++++---
 .../main/resources/operator/benchmarkCRD.yaml | 34 ++++++++-----
 .../example-benchmark-k8s-resource.yaml       |  7 ++-
 .../example-execution-k8s-resource.yaml       | 11 ++--
 .../main/resources/operator/executionCRD.yaml | 17 ++++---
 17 files changed, 123 insertions(+), 70 deletions(-)
 create mode 100644 theodolite-quarkus/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt

diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
index 1e3929da9..0113ff669 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
@@ -183,7 +183,7 @@ class TheodoliteController(
                 val configurationOverride = ConfigurationOverride()
                 configurationOverride.patcher = PatcherDefinition()
                 configurationOverride.patcher.type = "LabelPatcher"
-                configurationOverride.patcher.variableName = labelName
+                configurationOverride.patcher.config = mutableListOf(hashMapOf("key" to "variableName",  "value" to labelName))
                 configurationOverride.patcher.resource = it
                 configurationOverride.value = labelValue
                 additionalConfigOverrides.add(configurationOverride)
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
index c0d17244b..df80e9cbd 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
@@ -20,7 +20,5 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
  *
  */
 abstract class AbstractPatcher(
-    k8sResource: KubernetesResource,
-    container: String? = null,
-    variableName: String? = null
+    k8sResource: KubernetesResource
 ) : Patcher
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
index b640df1da..416aec74a 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
@@ -16,7 +16,7 @@ class EnvVarPatcher(
     private val k8sResource: KubernetesResource,
     private val container: String,
     private val variableName: String
-) : AbstractPatcher(k8sResource, container, variableName) {
+) : AbstractPatcher(k8sResource) {
 
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
index b29d8d992..8f6753372 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
@@ -11,7 +11,7 @@ import io.fabric8.kubernetes.api.model.apps.StatefulSet
  * @param container Container to be patched.
  */
 class ImagePatcher(private val k8sResource: KubernetesResource, private val container: String) :
-    AbstractPatcher(k8sResource, container) {
+    AbstractPatcher(k8sResource) {
 
     override fun <String> patch(imagePath: String) {
         if (k8sResource is Deployment) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/LabelPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
index d9feff007..5ee5807cd 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
@@ -8,10 +8,9 @@ import io.fabric8.kubernetes.api.model.apps.StatefulSet
 import io.fabric8.kubernetes.client.CustomResource
 
 class LabelPatcher(private val k8sResource: KubernetesResource, val variableName: String) :
-    AbstractPatcher(k8sResource, variableName) {
+    AbstractPatcher(k8sResource) {
 
     override fun <String> patch(labelValue: String) {
-        println("call patcher for resource $k8sResource !")
         if(labelValue is kotlin.String){
             when(k8sResource){
                 is Deployment -> {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
index 0a668a908..0e8cd553a 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
@@ -10,7 +10,7 @@ import io.fabric8.kubernetes.api.model.apps.Deployment
  * @param variableName The `label-key` of the node for which the `label-value` is to be patched.
  */
 class NodeSelectorPatcher(private val k8sResource: KubernetesResource, private val variableName: String) :
-    AbstractPatcher(k8sResource, variableName) {
+    AbstractPatcher(k8sResource) {
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
             k8sResource.spec.template.spec.nodeSelector = mapOf(variableName to value as kotlin.String)
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
index d7136740a..65489a969 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
@@ -4,16 +4,17 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import kotlin.math.pow
 
-private const val NUM_SENSORS = 4.0
-private const val LOAD_GEN_MAX_RECORDS = 150000
-
-class NumNestedGroupsLoadGeneratorReplicaPatcher(private val k8sResource: KubernetesResource) :
+class NumNestedGroupsLoadGeneratorReplicaPatcher(
+    private val k8sResource: KubernetesResource,
+    private val numSensors: String,
+    private val loadGenMaxRecords: String
+    ) :
     AbstractPatcher(k8sResource) {
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
             if (value is kotlin.String) {
-                val approxNumSensors = NUM_SENSORS.pow(Integer.parseInt(value).toDouble())
-                val loadGenInstances = (approxNumSensors + LOAD_GEN_MAX_RECORDS - 1) / LOAD_GEN_MAX_RECORDS
+                val approxNumSensors =  numSensors.toDouble().pow(Integer.parseInt(value).toDouble())
+                val loadGenInstances = (approxNumSensors + loadGenMaxRecords.toDouble() - 1) / loadGenMaxRecords.toDouble()
                 this.k8sResource.spec.replicas = loadGenInstances.toInt()
             }
         }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
index d29280a64..f6a06324e 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
@@ -3,14 +3,16 @@ package theodolite.patcher
 import io.fabric8.kubernetes.api.model.KubernetesResource
 import io.fabric8.kubernetes.api.model.apps.Deployment
 
-private const val LOAD_GEN_MAX_RECORDS = 150000
 
-class NumSensorsLoadGeneratorReplicaPatcher(private val k8sResource: KubernetesResource) :
+class NumSensorsLoadGeneratorReplicaPatcher(
+    private val k8sResource: KubernetesResource,
+    private val loadGenMaxRecords: String
+) :
     AbstractPatcher(k8sResource) {
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
             if (value is kotlin.String) {
-                val loadGenInstances = (Integer.parseInt(value) + LOAD_GEN_MAX_RECORDS - 1) / LOAD_GEN_MAX_RECORDS
+                val loadGenInstances = (Integer.parseInt(value) + loadGenMaxRecords.toInt() - 1) / loadGenMaxRecords.toInt()
                 this.k8sResource.spec.replicas = loadGenInstances
             }
         }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
index 58dd95e9d..29171e53d 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
@@ -28,27 +28,50 @@ class PatcherFactory {
         k8sResources: List<Pair<String, KubernetesResource>>
     ): Patcher {
         val resource =
-            k8sResources.filter { it.first == patcherDefinition.resource }.map { resource -> resource.second }.firstOrNull()
+            k8sResources.filter { it.first == patcherDefinition.resource }
+                .map { resource -> resource.second }
+                .firstOrNull()
                 ?: throw DeploymentFailedException("Could not find resource ${patcherDefinition.resource}")
 
+
         return when (patcherDefinition.type) {
-            "ReplicaPatcher" -> ReplicaPatcher(resource)
-            "NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher(resource)
-            "NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher(resource)
-            "EnvVarPatcher" -> EnvVarPatcher(resource, patcherDefinition.container, patcherDefinition.variableName)
-            "NodeSelectorPatcher" -> NodeSelectorPatcher(resource, patcherDefinition.variableName)
+            "ReplicaPatcher" -> ReplicaPatcher(
+                k8sResource = resource
+            )
+            "NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher(
+                k8sResource = resource,
+                loadGenMaxRecords = patcherDefinition.getValueByKey("loadGenMaxRecords"),
+                numSensors = patcherDefinition.getValueByKey("numSensors")
+            )
+            "NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher(
+                k8sResource = resource,
+                loadGenMaxRecords = patcherDefinition.getValueByKey("loadGenMaxRecords")
+            )
+            "EnvVarPatcher" -> EnvVarPatcher(
+                k8sResource = resource,
+                container = patcherDefinition.getValueByKey("container"),
+                variableName = patcherDefinition.getValueByKey("variableName")
+            )
+            "NodeSelectorPatcher" -> NodeSelectorPatcher(
+                k8sResource = resource,
+                variableName = patcherDefinition.getValueByKey("variableName"))
             "ResourceLimitPatcher" -> ResourceLimitPatcher(
-                resource,
-                patcherDefinition.container,
-                patcherDefinition.variableName
+                k8sResource = resource,
+                container = patcherDefinition.getValueByKey("container"),
+                limitedResource = patcherDefinition.getValueByKey("limitedResource")
             )
             "ResourceRequestPatcher" -> ResourceRequestPatcher(
-                resource,
-                patcherDefinition.container,
-                patcherDefinition.variableName
+                k8sResource = resource,
+                container = patcherDefinition.getValueByKey("container"),
+                requestedResource = patcherDefinition.getValueByKey("requestedResource")
+            )
+            "SchedulerNamePatcher" -> SchedulerNamePatcher(
+                k8sResource = resource
+            )
+            "LabelPatcher" -> LabelPatcher(
+                k8sResource = resource,
+                variableName = patcherDefinition.getValueByKey("variableName")
             )
-            "SchedulerNamePatcher" -> SchedulerNamePatcher(resource)
-            "LabelPatcher" -> LabelPatcher(resource, patcherDefinition.variableName)
             else -> throw IllegalArgumentException("Patcher type ${patcherDefinition.type} not found")
         }
     }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
index 30f82e804..1a6fa35a9 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
@@ -18,7 +18,7 @@ class ResourceLimitPatcher(
     private val k8sResource: KubernetesResource,
     private val container: String,
     private val limitedResource: String
-) : AbstractPatcher(k8sResource, container, limitedResource) {
+) : AbstractPatcher(k8sResource) {
 
     override fun <String> patch(value: String) {
         when (k8sResource) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
index 24b2a6d40..9bf8c3c72 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
@@ -18,7 +18,7 @@ class ResourceRequestPatcher(
     private val k8sResource: KubernetesResource,
     private val container: String,
     private val requestedResource: String
-) : AbstractPatcher(k8sResource, container, requestedResource) {
+) : AbstractPatcher(k8sResource) {
 
     override fun <String> patch(value: String) {
         when (k8sResource) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt
new file mode 100644
index 000000000..c103ef1f3
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt
@@ -0,0 +1,5 @@
+package theodolite.util
+
+class InvalidPatcherConfigurationException(message:String): Exception(message) {
+}
+
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt
index b24f887d6..508f6264e 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt
@@ -1,6 +1,7 @@
 package theodolite.util
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import com.fasterxml.jackson.databind.annotation.JsonSerialize
 import io.quarkus.runtime.annotations.RegisterForReflection
 
 /**
@@ -19,13 +20,24 @@ class PatcherDefinition {
      */
     lateinit var resource: String
 
-    /**
-     * The container which the patcher is applied to
-     */
-    lateinit var container: String
+    @JsonSerialize
+    lateinit var config: MutableList<Map<String, String>>
 
-    /**
-     * The variable name for the patcher
-     */
-    lateinit var variableName: String
+    fun getValueByKey(key: String): String {
+        val value = this.config
+            .filter { it["key"] == key }
+            .map {
+                try {
+                    it.getValue("value")
+                } catch (e: Exception) {
+                    throw InvalidPatcherConfigurationException("No value found for key $key.")
+                }
+            }
+
+        return when {
+            value.isEmpty() -> throw InvalidPatcherConfigurationException("Required argument $key missing.")
+            value.size > 1 -> throw InvalidPatcherConfigurationException("Can not handle duplicate declaration for key $key.")
+            else -> value.first()
+        }
+    }
 }
diff --git a/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml b/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml
index 4e481c512..9d3220216 100644
--- a/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml
@@ -54,12 +54,17 @@ spec:
                           resource:
                             type: string
                             default: ""
-                          container:
-                            type: string
-                            default: ""
-                          variableName:
-                            type: string
-                            default: ""
+                          config:
+                            type: array
+                            items:
+                              type: object
+                              properties:
+                                key:
+                                  type: string
+                                  default: ""
+                                value:
+                                  type: string
+                                  default: ""
               loadTypes:
                 type: array
                 minItems: 1
@@ -80,12 +85,17 @@ spec:
                           resource:
                             type: string
                             default: ""
-                          container:
-                            type: string
-                            default: ""
-                          variableName:
-                            type: string
-                            default: ""
+                          config:
+                            type: array
+                            items:
+                              type: object
+                              properties:
+                                key:
+                                  type: string
+                                  default: ""
+                                value:
+                                  type: string
+                                  default: ""
               kafkaConfig:
                 type: object
                 properties:
diff --git a/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml b/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml
index 16c14b665..e0df9e462 100644
--- a/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml
@@ -22,8 +22,11 @@ spec:
       patchers:
         - type: "EnvVarPatcher"
           resource: "uc1-load-generator-deployment.yaml"
-          container: "workload-generator"
-          variableName: "NUM_SENSORS"
+          config:
+            - key: container
+              value: "workload-generator"
+            - key: variableName
+              value: "NUM_SENSORS"
   kafkaConfig:
     bootstrapServer: "localhost:31290"
     topics:
diff --git a/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml b/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml
index 4227020e7..5d7596663 100644
--- a/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml
@@ -27,15 +27,10 @@ spec:
     restrictions:
       - "LowerBound"
   configOverrides:
-    - patcher:
-        type: "NodeSelectorPatcher"
-        resource: "uc1-load-generator-deployment.yaml"
-        container: ""
-        variableName: "env"
-      value: "prod"
     - patcher:
         type: "NodeSelectorPatcher"
         resource: "uc1-kstreams-deployment.yaml"
-        container: ""
-        variableName: "env"
+        config: 
+          - key: variableName
+            value: env
       value: "prod"
diff --git a/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml b/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml
index 8e1189572..140140d09 100644
--- a/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml
@@ -95,12 +95,17 @@ spec:
                         resource:
                           type: string
                           default: ""
-                        container:
-                          type: string
-                          default: ""
-                        variableName:
-                          type: string
-                          default: ""
+                        config:
+                          type: array
+                          items:
+                            type: object
+                            properties:
+                              key:
+                                type: string
+                                default: ""
+                              value:
+                                type: string
+                                default: ""
                     value:
                       type: string
           status:
-- 
GitLab