From 540544de1aa4cd7691e97f51bc757320feb7990f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=B6ren=20Henning?= <soeren.henning@email.uni-kiel.de>
Date: Sat, 3 Dec 2022 17:14:44 +0100
Subject: [PATCH] Add decorating patcher

---
 .../patcher/AbstractStringPatcher.kt          |  7 ++--
 .../patcher/ConfigMapYamlPatcher.kt           |  2 +-
 .../kubernetes/patcher/DecoratingPatcher.kt   | 35 +++++++++++++++++++
 .../kubernetes/patcher/PatcherFactory.kt      | 22 ++++++++----
 4 files changed, 57 insertions(+), 9 deletions(-)
 create mode 100644 theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/DecoratingPatcher.kt

diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/AbstractStringPatcher.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/AbstractStringPatcher.kt
index a8b38630f..7048a78ee 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/AbstractStringPatcher.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/AbstractStringPatcher.kt
@@ -6,12 +6,15 @@ import io.fabric8.kubernetes.client.utils.Serialization
 /**
  * A Patcher is able to modify values of a Kubernetes resource, see [Patcher].
  */
-abstract class AbstractStringPatcher : Patcher {
+abstract class AbstractStringPatcher(
+    val prefix: String = "",
+    val suffix: String = ""
+) : Patcher {
 
     final override fun patch(resources: List<HasMetadata>, value: String) : List<HasMetadata> {
         return resources
             .map { Serialization.clone(it)}
-            .map { patchSingleResource(it, value) }
+            .map { patchSingleResource(it, prefix + value) }
     }
 
     abstract fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt
index 210fe8c26..3c495331f 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/ConfigMapYamlPatcher.kt
@@ -13,7 +13,7 @@ import org.yaml.snakeyaml.Yaml
  */
 class ConfigMapYamlPatcher(
     private val fileName: String,
-    private val variableName: String
+    private val variableName: String,
 ) : AbstractStringPatcher() {
 
     override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/DecoratingPatcher.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/DecoratingPatcher.kt
new file mode 100644
index 000000000..2cd2265b7
--- /dev/null
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/DecoratingPatcher.kt
@@ -0,0 +1,35 @@
+package rocks.theodolite.kubernetes.patcher
+
+import io.fabric8.kubernetes.api.model.HasMetadata
+import mu.KotlinLogging
+
+private val logger = KotlinLogging.logger {}
+
+/**
+ * A decorating [Patcher] to modifies a value by a factor, a prefix and a suffix. All modifications are optional. The
+ * factor only has an effect if the supplied value is an integer.
+ */
+class DecoratingPatcher(
+    private val innerPatcher: Patcher,
+    private val prefix: String?,
+    private val suffix: String?,
+    private val factor: Int?
+) : Patcher {
+
+    override fun patch(resources: List<HasMetadata>, value: String) : List<HasMetadata> {
+        return this.innerPatcher.patch(resources, (prefix ?: "") + multiply(value) + (suffix ?: ""))
+    }
+
+    private fun multiply(value: String): String {
+        if (this.factor == null) {
+            return value
+        }
+        val valueAsInt = value.toIntOrNull()
+        if (valueAsInt == null) {
+            logger.warn { "Patcher value cannot be parsed as Int. Ignoring factor." }
+            return value
+        }
+        return valueAsInt.times(factor).toString()
+    }
+
+}
diff --git a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/PatcherFactory.kt b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/PatcherFactory.kt
index 7bfde3e38..4b75999e7 100644
--- a/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/PatcherFactory.kt
+++ b/theodolite/src/main/kotlin/rocks/theodolite/kubernetes/patcher/PatcherFactory.kt
@@ -32,9 +32,14 @@ class PatcherFactory {
                         container = patcher.properties["container"] ?: throwInvalid(patcher),
                         variableName = patcher.properties["variableName"] ?: throwInvalid(patcher)
                     )
-                    "EnvVarPatcher" -> EnvVarPatcher(
-                        container = patcher.properties["container"] ?: throwInvalid(patcher),
-                        variableName = patcher.properties["variableName"] ?: throwInvalid(patcher)
+                    "EnvVarPatcher" -> DecoratingPatcher(
+                        EnvVarPatcher(
+                            container = patcher.properties["container"] ?: throwInvalid(patcher),
+                            variableName = patcher.properties["variableName"] ?: throwInvalid(patcher)
+                        ),
+                        prefix = patcher.properties["prefix"],
+                        suffix = patcher.properties["suffix"],
+                        factor = patcher.properties["factor"]?.toInt(),
                     )
                     "NodeSelectorPatcher" -> NodeSelectorPatcher(
                         variableName = patcher.properties["variableName"] ?: throwInvalid(patcher)
@@ -64,9 +69,14 @@ class PatcherFactory {
                     "ImagePatcher" -> ImagePatcher(
                         container = patcher.properties["container"] ?: throwInvalid(patcher)
                     )
-                    "ConfigMapYamlPatcher" -> ConfigMapYamlPatcher(
-                        fileName = patcher.properties["fileName"] ?: throwInvalid(patcher),
-                        variableName = patcher.properties["variableName"] ?: throwInvalid(patcher)
+                    "ConfigMapYamlPatcher" -> DecoratingPatcher(
+                            ConfigMapYamlPatcher(
+                            fileName = patcher.properties["fileName"] ?: throwInvalid(patcher),
+                            variableName = patcher.properties["variableName"] ?: throwInvalid(patcher)
+                        ),
+                        prefix = patcher.properties["prefix"],
+                        suffix = patcher.properties["suffix"],
+                        factor = patcher.properties["factor"]?.toInt(),
                     )
                     "NamePatcher" -> NamePatcher()
                     "ServiceSelectorPatcher" -> ServiceSelectorPatcher(
-- 
GitLab