diff --git a/execution/helm/templates/theodolite/crd-benchmark.yaml b/execution/helm/templates/theodolite/crd-benchmark.yaml index 848ecb37213f2810853a47fd45d3869198acd720..319eee18cee87d12cd7051e5fc3414f99c8d8a30 100644 --- a/execution/helm/templates/theodolite/crd-benchmark.yaml +++ b/execution/helm/templates/theodolite/crd-benchmark.yaml @@ -55,12 +55,12 @@ spec: resource: type: string default: "" - container: - type: string - default: "" - variableName: - type: string - default: "" + config: + type: object + additionalProperties: true + x-kubernetes-map-type: "granular" + default: + "": "" loadTypes: type: array minItems: 1 @@ -81,12 +81,12 @@ spec: resource: type: string default: "" - container: - type: string - default: "" - variableName: - type: string - default: "" + config: + type: object + additionalProperties: true + x-kubernetes-map-type: "granular" + default: + "": "" kafkaConfig: type: object properties: diff --git a/execution/helm/templates/theodolite/crd-execution.yaml b/execution/helm/templates/theodolite/crd-execution.yaml index 92835ee1d5a016d0fe6e2db874ae222d7f49f461..41ba1b0b5b19b53d9b7caec48241285edf4ba396 100644 --- a/execution/helm/templates/theodolite/crd-execution.yaml +++ b/execution/helm/templates/theodolite/crd-execution.yaml @@ -1,4 +1,3 @@ -{{- if .Values.executionCRD.create -}} apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -96,12 +95,12 @@ spec: resource: type: string default: "" - container: - type: string - default: "" - variableName: - type: string - default: "" + config: + type: object + additionalProperties: true + x-kubernetes-map-type: "granular" + default: + "": "" value: type: string status: @@ -127,6 +126,4 @@ spec: jsonPath: .metadata.creationTimestamp subresources: status: {} - scope: Namespaced - status: {} -{{- end }} \ No newline at end of file + scope: Namespaced \ No newline at end of file diff --git a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-operator.yaml index 0c8e9edf92afcb6de19a46904dc8d30a3fcda87d..b80b572dfd30e9c056d3c01ba17cc662d70fc749 100644 --- a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-operator.yaml @@ -24,7 +24,7 @@ spec: properties: container: "workload-generator" variableName: "NUM_SENSORS" - - type: NumSensorsLoadGeneratorReplicaPatcher + - type: "NumSensorsLoadGeneratorReplicaPatcher" resource: "uc1-load-generator-deployment.yaml" properties: loadGenMaxRecords: "15000" diff --git a/theodolite-quarkus/config/README.md b/theodolite-quarkus/config/README.md index 4f53d87ba9ac12099091faa315913cf93ed62bb7..23337d77375ebba8f624e7a11f714502fe3d5e67 100644 --- a/theodolite-quarkus/config/README.md +++ b/theodolite-quarkus/config/README.md @@ -19,14 +19,16 @@ resourceTypes: patchers: - type: String resources: String - <Patcher Arguments> ... + properties: + <Patcher Arguments> ... ... loadTypes: - typeName: String patchers: - type: String resources: String - <Patcher Arguments> ... + properties: + <Patcher Arguments> ... ... kafkaConfig: bootstrapServer: String @@ -49,7 +51,7 @@ The properties have the following definitions: * **patchers**: List of [patchers](#Patchers) used to scale this resource type. Each patcher has the following structure: * **type**: Type of the [patcher](#Patchers). The concrete types can be looked up in the list of [patchers](#Patchers). * **resources**: Specifies the Kubernetes resource to be patched. - * **Patcher Arguments**: (Optional) Patcher specific additional arguments. + * **properties**: *Patcher Arguments*: (Optional) Patcher specific additional arguments. * **loadTypes**: A list of load types that can be scaled for this *benchmark*. For each load type the concrete values are defined in the *execution* object. Each load type has the following structure: * **typeName**: Name of the load type. * **patchers**: List of patchers used to scale * **resourceTypes**: A list of resource types that can be scaled for this *benchmark*. For each resource type the concrete values are defined in the *execution* resource object.Each resource type has the following structure: @@ -57,7 +59,7 @@ The properties have the following definitions: * **patchers**: List of patchers used to scale this resource type. Each patcher has the following structure: * **type**: Type of the Patcher. The concrete types can be looked up in the list of patchers. * **resources**: Specifies the Kubernetes resource to be patched. - * **Patcher Arguments**: (Optional) Patcher specific additional arguments. + * **properties**: *Patcher Arguments*: (Optional) Patcher specific additional arguments as Map<String, String>. * **kafkaConfig**: Contains the Kafka configuration. * **bootstrapServers**: The bootstrap servers connection string. * **topics**: List of topics to be created for each [experiment](#Experiment). Alternative theodolite offers the possibility to remove certain topics after each experiment. @@ -105,7 +107,8 @@ configurationOverrides: - patcher: type: String resource: String - <Patcher Arguments> ... + properties: + <Patcher Arguments> ... ... ``` @@ -136,7 +139,7 @@ The properties have the following definitions: * **patcher**: Patcher used to patch a resource. Each patcher has the following structure: * **type**: Type of the Patcher. The concrete types can be looked up in the list of patchers. * **resources**: Specifies the Kubernetes resource to be patched. - * **Patcher Arguments**: (Optional) Patcher specific additional arguments. + * **properties**: *Patcher Arguments*: (Optional) Patcher specific additional arguments. ## Patchers @@ -159,19 +162,22 @@ The properties have the following definitions: * **EnvVarPatcher**: Allows to modify the value of an environment variable for a container in a kubernetes deployment. * **type**: "EnvVarPatcher" * **resource**: "uc1-load-generator-deployment.yaml" - * **container**: "workload-generator" - * **variableName**: "NUM_SENSORS" + * **properties**: + * container: "workload-generator" + * variableName: "NUM_SENSORS" * **NodeSelectorPatcher**: Changes the node selection field in kubernetes resources. * **type**: "NodeSelectorPatcher" * **resource**: "uc1-load-generator-deployment.yaml" - * **variableName**: "env" + * **properties**: + * variableName: "env" * **value**: "prod" * **ResourceLimitPatcher**: Changes the resource limit for a kubernetes resource. * **resource**: "uc1-kstreams-deployment.yaml" - * **container**: "uc-application" - * **variableName**: "cpu" or "memory" + * **properties**: + * container: "uc-application" + * variableName: "cpu" or "memory" * **value**:"1000m" or "2Gi" * **SchedulerNamePatcher**: Changes the sheduler for kubernetes resources. @@ -182,7 +188,8 @@ The properties have the following definitions: * **ImagePatcher**: Changes the image of a kubernetes resource. Currently not fully implemented. * **type**: "ImagePatcher" * **resource**: "uc1-kstreams-deployment.yaml" - * **container**: "uc-application" + * **properties**: + * container: "uc-application" * **value**: "dockerhubrepo/imagename" diff --git a/theodolite-quarkus/config/example-execution-yaml-resource.yaml b/theodolite-quarkus/config/example-execution-yaml-resource.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e46a6cf417442b851650fe9699f73e1367dcc794 --- /dev/null +++ b/theodolite-quarkus/config/example-execution-yaml-resource.yaml @@ -0,0 +1,53 @@ +name: example-execution +benchmark: "uc1-kstreams" +load: + loadType: "NumSensors" + loadValues: [25000, 50000, 75000, 100000, 125000, 150000] +resources: + resourceType: "Instances" + resourceValues: [1, 2, 3, 4, 5] +slos: + - sloType: "lag trend" + threshold: 2000 + prometheusUrl: "http://prometheus-operated:9090" + externalSloUrl: "http://localhost:80/evaluate-slope" + offset: 0 + warmup: 60 # in seconds +execution: + strategy: "LinearSearch" + duration: 300 # in seconds + repetitions: 1 + loadGenerationDelay: 30 # in seconds, optional field, default is 0 seconds + restrictions: + - "LowerBound" +configOverrides: + - patcher: + type: "NodeSelectorPatcher" + resource: "uc1-load-generator-deployment.yaml" + properties: + variableName: "env" + value: "prod" + - patcher: + type: "NodeSelectorPatcher" + resource: "uc1-kstreams-deployment.yaml" + properties: + variableName: "env" + value: "prod" + - patcher: + type: "ResourceLimitPatcher" + resource: "uc1-kstreams-deployment.yaml" + properties: + container: "uc-application" + limitedResource: "cpu" + value: "1000m" + - patcher: + type: "ResourceLimitPatcher" + resource: "uc1-kstreams-deployment.yaml" + properties: + container: "uc-application" + limitedResource: "memory" + value: "2Gi" +# - patcher: +# type: "SchedulerNamePatcher" +# resource: "uc1-kstreams-deployment.yaml" +# value: "random-scheduler" diff --git a/theodolite-quarkus/config/example-operator-execution.yaml b/theodolite-quarkus/config/example-operator-execution.yaml new file mode 100644 index 0000000000000000000000000000000000000000..9b2a1facbd8be3411407dfcf3cad39fd9f3de6b6 --- /dev/null +++ b/theodolite-quarkus/config/example-operator-execution.yaml @@ -0,0 +1,57 @@ +apiVersion: theodolite.com/v1 +kind: execution +metadata: + name: example-execution +spec: + benchmark: "uc1-kstreams" + load: + loadType: "NumSensors" + loadValues: [25000, 50000, 75000, 100000, 125000, 150000] + resources: + resourceType: "Instances" + resourceValues: [1, 2, 3, 4, 5] + slos: + - sloType: "lag trend" + threshold: 2000 + prometheusUrl: "http://prometheus-operated:9090" + externalSloUrl: "http://localhost:80/evaluate-slope" + offset: 0 + warmup: 60 # in seconds + execution: + strategy: "LinearSearch" + duration: 300 # in seconds + repetitions: 1 + loadGenerationDelay: 30 # in seconds + restrictions: + - "LowerBound" + configOverrides: + # - patcher: + # type: "NodeSelectorPatcher" + # resource: "uc1-load-generator-deployment.yaml" + # properties: + # variableName: "env" + # value: "prod" + # - patcher: + # type: "NodeSelectorPatcher" + # resource: "uc1-kstreams-deployment.yaml" + # properties: + # variableName: "env" + # value: "prod" + # - patcher: + # type: "ResourceLimitPatcher" + # resource: "uc1-kstreams-deployment.yaml" + # properties: + # container: "uc-application" + # limitedResource: "cpu" + # value: "1000m" + # - patcher: + # type: "ResourceLimitPatcher" + # resource: "uc1-kstreams-deployment.yaml" + # properties: + # container: "uc-application" + # limitedResource: "memory" + # value: "2Gi" + # - patcher: + # type: "SchedulerNamePatcher" + # resource: "uc1-kstreams-deployment.yaml" + # value: "random-scheduler" diff --git a/theodolite-quarkus/crd/crd-benchmark.yaml b/theodolite-quarkus/crd/crd-benchmark.yaml index 4e481c51231999e2e7a1e75ecbc018d40db75c91..b76821f6e7cca5408f604ba9bbf83cf1b43a37de 100644 --- a/theodolite-quarkus/crd/crd-benchmark.yaml +++ b/theodolite-quarkus/crd/crd-benchmark.yaml @@ -54,12 +54,11 @@ spec: resource: type: string default: "" - container: - type: string - default: "" - variableName: - type: string - default: "" + properties: + type: object + additionalProperties: true + x-kubernetes-map-type: "granular" + default: {} loadTypes: type: array minItems: 1 @@ -80,12 +79,11 @@ spec: resource: type: string default: "" - container: - type: string - default: "" - variableName: - type: string - default: "" + properties: + type: object + additionalProperties: true + x-kubernetes-map-type: "granular" + default: {} kafkaConfig: type: object properties: diff --git a/theodolite-quarkus/crd/crd-execution.yaml b/theodolite-quarkus/crd/crd-execution.yaml index 8e1189572ee993c37dd565fc62a66996654766f2..b984f3ebe5ca7c8868adb9d3593e5d87d73fc2bd 100644 --- a/theodolite-quarkus/crd/crd-execution.yaml +++ b/theodolite-quarkus/crd/crd-execution.yaml @@ -95,12 +95,11 @@ spec: resource: type: string default: "" - container: - type: string - default: "" - variableName: - type: string - default: "" + properties: + type: object + additionalProperties: true + x-kubernetes-map-type: "granular" + default: {} value: type: string status: 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 1e3929da98be060e2cbebf305dbae2f25519798a..3053c364e2d6d9bc9797c190f0a87d861089b556 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.properties = mutableMapOf("variableName" 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 c0d17244b6a7a3f37b8d8a57713659b85b9b65b1..df80e9cbd2503685a7dbed35db5319920dfc42cb 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 b640df1da2ca1c139bb5b02e9e42bad9e7d08d74..416aec74a3af9b74594f5e6cd018682bf91cbf63 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 b29d8d9925311aa25b7336dcd6805783ca62c3e7..8f6753372076c119324dc962112928253633b6b0 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 d9feff00726c8c73483118276eeae7b7975d8c8e..5ee5807cd8378c9f2bbd62435203208d61131f15 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 0a668a908e66577f96ea1268b85a38ad73bb16a7..0e8cd553a6c6a9ed6fa2c8cc1b84e4cfebe79d73 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 d7136740a7e17f956eed16bc6e3fcd4954ab91b8..65489a96974ad566fe7cbd88cf6ff7fb49135e1d 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 d29280a648cd4c912b8e2717b51c4f9c3f8a2271..f6a06324e36d7942d3944a492fee263f428376c1 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 58dd95e9d582911a209a1173a0f58f8fac729c86..45e50113c964d671962fadc718994a29b2da81f4 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt @@ -2,6 +2,7 @@ package theodolite.patcher import io.fabric8.kubernetes.api.model.KubernetesResource import theodolite.util.DeploymentFailedException +import theodolite.util.InvalidPatcherConfigurationException import theodolite.util.PatcherDefinition /** @@ -28,28 +29,56 @@ 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) - "ResourceLimitPatcher" -> ResourceLimitPatcher( - resource, - patcherDefinition.container, - patcherDefinition.variableName - ) - "ResourceRequestPatcher" -> ResourceRequestPatcher( - resource, - patcherDefinition.container, - patcherDefinition.variableName - ) - "SchedulerNamePatcher" -> SchedulerNamePatcher(resource) - "LabelPatcher" -> LabelPatcher(resource, patcherDefinition.variableName) - else -> throw IllegalArgumentException("Patcher type ${patcherDefinition.type} not found") + return try { + when (patcherDefinition.type) { + "ReplicaPatcher" -> ReplicaPatcher( + k8sResource = resource + ) + "NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher( + k8sResource = resource, + loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"] !!, + numSensors = patcherDefinition.properties["numSensors"] !! + ) + "NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher( + k8sResource = resource, + loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"] !! + ) + "EnvVarPatcher" -> EnvVarPatcher( + k8sResource = resource, + container = patcherDefinition.properties["container"] !!, + variableName = patcherDefinition.properties["variableName"] !! + ) + "NodeSelectorPatcher" -> NodeSelectorPatcher( + k8sResource = resource, + variableName = patcherDefinition.properties["variableName"] !! + ) + "ResourceLimitPatcher" -> ResourceLimitPatcher( + k8sResource = resource, + container = patcherDefinition.properties["container"] !!, + limitedResource = patcherDefinition.properties["limitedResource"] !! + ) + "ResourceRequestPatcher" -> ResourceRequestPatcher( + k8sResource = resource, + container = patcherDefinition.properties["container"] !!, + requestedResource = patcherDefinition.properties["requestedResource"] !! + ) + "SchedulerNamePatcher" -> SchedulerNamePatcher( + k8sResource = resource + ) + "LabelPatcher" -> LabelPatcher( + k8sResource = resource, + variableName = patcherDefinition.properties["variableName"] !! + ) + else -> throw InvalidPatcherConfigurationException("Patcher type ${patcherDefinition.type} not found.") + } + } catch (e: Exception) { + throw InvalidPatcherConfigurationException("Could not create patcher with type ${patcherDefinition.type}" + + " Probably a required patcher argument was not specified." ) } } } diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt index 30f82e804f23b770457ec968f25ba7c00d72aefd..1a6fa35a944d00634ec0607b0bff34f4cb9d9b9c 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 24b2a6d40525f16448b77c50fba8aba0969d075a..9bf8c3c72f656d326ca3070cd5843778e5cdff42 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 0000000000000000000000000000000000000000..c103ef1f35a1b3ffa56dad50c7cf6c1db51eb57f --- /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 b24f887d6ff6e3096a2e740f541861d76804775b..6ec0cce36751ec0343d40aa49fefa44f4c7fc918 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,6 @@ class PatcherDefinition { */ lateinit var resource: String - /** - * The container which the patcher is applied to - */ - lateinit var container: String - - /** - * The variable name for the patcher - */ - lateinit var variableName: String + @JsonSerialize + lateinit var properties: MutableMap<String, String> } 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 new file mode 100644 index 0000000000000000000000000000000000000000..b81bbcd442834136283dc080f5f6a79bbc1cd415 --- /dev/null +++ b/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml @@ -0,0 +1,29 @@ +apiVersion: theodolite.com/v1 +kind: execution +metadata: + name: theodolite-example-execution +spec: + benchmark: uc1-kstreams + load: + loadType: "NumSensors" + loadValues: + - 50000 + resources: + resourceType: "Instances" + resourceValues: + - 1 + slos: + - sloType: "lag trend" + threshold: 1000 + prometheusUrl: "http://localhost:32656" + externalSloUrl: "http://localhost:80/evaluate-slope" + offset: 0 + warmup: 0 + execution: + strategy: "LinearSearch" + duration: 60 + repetitions: 1 + loadGenerationDelay: 30 # in seconds + restrictions: + - "LowerBound" + configOverrides: [] \ No newline at end of file diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt index 4f4308a35df598dc4932a8ac89a6c07fb967e416..4ae9ce23b31204b366dce7bcf000e4114d7f3f8f 100644 --- a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt +++ b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt @@ -31,27 +31,32 @@ class ResourceLimitPatcherTest { val k8sResource = loader.loadK8sResource("Deployment", testPath + fileName) as Deployment val defCPU = PatcherDefinition() - defCPU.variableName = "cpu" defCPU.resource = "cpu-memory-deployment.yaml" - defCPU.container = "uc-application" defCPU.type = "ResourceLimitPatcher" + defCPU.properties = mutableMapOf( + "limitedResource" to "cpu", + "container" to "application" + ) val defMEM = PatcherDefinition() - defMEM.variableName = "memory" defMEM.resource = "cpu-memory-deployment.yaml" - defMEM.container = "uc-application" defMEM.type = "ResourceLimitPatcher" + defMEM.properties = mutableMapOf( + "limitedResource" to "memory", + "container" to "uc-application" + ) patcherFactory.createPatcher( patcherDefinition = defCPU, k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)) ).patch(value = cpuValue) + patcherFactory.createPatcher( patcherDefinition = defMEM, k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)) ).patch(value = memValue) - k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container } + k8sResource.spec.template.spec.containers.filter { it.name == defCPU.properties["container"] !! } .forEach { assertTrue(it.resources.limits["cpu"].toString() == cpuValue) assertTrue(it.resources.limits["memory"].toString() == memValue) diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt index 7214422705a64f507a196a4b5f9b334665407422..6f232961871c9d11929fc912a483e6e805cc7daf 100644 --- a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt +++ b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt @@ -31,16 +31,20 @@ class ResourceRequestPatcherTest { val k8sResource = loader.loadK8sResource("Deployment", testPath + fileName) as Deployment val defCPU = PatcherDefinition() - defCPU.variableName = "cpu" defCPU.resource = "cpu-memory-deployment.yaml" - defCPU.container = "uc-application" defCPU.type = "ResourceRequestPatcher" + defCPU.properties = mutableMapOf( + "requestedResource" to "cpu", + "container" to "application" + ) val defMEM = PatcherDefinition() - defMEM.variableName = "memory" defMEM.resource = "cpu-memory-deployment.yaml" - defMEM.container = "uc-application" defMEM.type = "ResourceRequestPatcher" + defMEM.properties = mutableMapOf( + "requestedResource" to "memory", + "container" to "application" + ) patcherFactory.createPatcher( patcherDefinition = defCPU, @@ -51,7 +55,7 @@ class ResourceRequestPatcherTest { k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)) ).patch(value = memValue) - k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container } + k8sResource.spec.template.spec.containers.filter { it.name == defCPU.properties["container"] !! } .forEach { assertTrue(it.resources.requests["cpu"].toString() == cpuValue) assertTrue(it.resources.requests["memory"].toString() == memValue)