diff --git a/execution/helm/.gitignore b/execution/helm/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..80bf7fc709ac6d08e703fe9f24d7d5776e26830e --- /dev/null +++ b/execution/helm/.gitignore @@ -0,0 +1 @@ +charts \ No newline at end of file diff --git a/execution/helm/templates/theodolite/random-scheduler/cluster-role-binding.yaml b/execution/helm/templates/theodolite/random-scheduler/cluster-role-binding.yaml new file mode 100644 index 0000000000000000000000000000000000000000..658f75c8c5018fe5b9f47cf9619bb4ee5b26b8e5 --- /dev/null +++ b/execution/helm/templates/theodolite/random-scheduler/cluster-role-binding.yaml @@ -0,0 +1,14 @@ +{{- if .Values.randomScheduler.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "theodolite.fullname" . }}-random-scheduler +subjects: +- kind: ServiceAccount + name: {{ include "theodolite.fullname" . }}-random-scheduler + namespace: kube-system +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: system:kube-scheduler +{{- end }} diff --git a/execution/helm/templates/theodolite/random-scheduler/deployment.yaml b/execution/helm/templates/theodolite/random-scheduler/deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..35a6ad027b93446a2bb97e2ebd67f2e27652e99a --- /dev/null +++ b/execution/helm/templates/theodolite/random-scheduler/deployment.yaml @@ -0,0 +1,30 @@ +{{- if .Values.randomScheduler.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "theodolite.fullname" . }}-random-scheduler + labels: + app: {{ include "theodolite.fullname" . }} + component: random-scheduler + namespace: kube-system +spec: + replicas: 1 + selector: + matchLabels: + app: {{ include "theodolite.fullname" . }} + component: random-scheduler + template: + metadata: + labels: + app: {{ include "theodolite.fullname" . }} + component: random-scheduler + spec: + serviceAccount: {{ include "theodolite.fullname" . }}-random-scheduler + containers: + - name: random-scheduler + image: ghcr.io/cau-se/theodolite-random-scheduler:theodolite-kotlin-latest + #imagePullPolicy: Always + env: + - name: TARGET_NAMESPACE + value: {{ .Release.Namespace }} +{{- end }} diff --git a/execution/helm/templates/theodolite/random-scheduler/service-account.yaml b/execution/helm/templates/theodolite/random-scheduler/service-account.yaml new file mode 100644 index 0000000000000000000000000000000000000000..babfff17b46d62e7e820fcb9dc8a35d73b4e6538 --- /dev/null +++ b/execution/helm/templates/theodolite/random-scheduler/service-account.yaml @@ -0,0 +1,10 @@ +{{- if .Values.randomScheduler.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: kube-system + name: {{ include "theodolite.fullname" . }}-random-scheduler + labels: + app: {{ include "theodolite.fullname" . }} + component: random-scheduler +{{- end }} diff --git a/execution/helm/values.yaml b/execution/helm/values.yaml index 67dab74c3931ce13a1ab0f7504a946a208b4dfb8..b4f2ffdea14c4c98a5b23b8f15056880a190e1a4 100644 --- a/execution/helm/values.yaml +++ b/execution/helm/values.yaml @@ -92,8 +92,9 @@ cp-helm-charts: "replica.fetch.max.bytes": "134217728" # 128 MB #default.replication.factor: 1 # "min.insync.replicas": 2 - # "auto.create.topics.enable": false - "log.retention.ms": "10000" # 10s + "auto.create.topics.enable": false + #"log.retention.ms": "10000" # 10s + "log.retention.ms": "7200000" # 2h "metrics.sample.window.ms": "5000" #5s "advertised.listeners": |- EXTERNAL://${HOST_IP}:$((31090 + ${KAFKA_BROKER_ID})) @@ -248,3 +249,10 @@ serviceAccount: rbac: create: true + +randomScheduler: + enabled: true + rbac: + create: true + serviceAccount: + create: true diff --git a/slope-evaluator/README.md b/slope-evaluator/README.md index 5929fb157a7c783bd37497885a5e3bc373b84aa0..12e8a61783532efce9e8722f500cf5ff880bace7 100644 --- a/slope-evaluator/README.md +++ b/slope-evaluator/README.md @@ -8,7 +8,7 @@ For development: uvicorn main:app --reload ``` -Build the docker image: +## Build the docker image: ```sh docker build . -t theodolite-evaluator diff --git a/theodolite-quarkus/README.md b/theodolite-quarkus/README.md index bb99f34e80f8b61b42f9b10b4c1d988871b74cb0..fc1d1bfe4a9c20a515cf6e69208657f74694d80e 100644 --- a/theodolite-quarkus/README.md +++ b/theodolite-quarkus/README.md @@ -1,4 +1,4 @@ -# theodolite-quarkus project +# Theodolite-quarkus project This project uses Quarkus, the Supersonic Subatomic Java Framework. @@ -6,7 +6,8 @@ If you want to learn more about Quarkus, please visit its website: https://quark ## Running the application in dev mode -You can run your application in dev mode that enables live coding using: +You can run your application in dev mode using: + ```shell script ./gradlew quarkusDev ``` @@ -14,13 +15,16 @@ You can run your application in dev mode that enables live coding using: ## Packaging and running the application The application can be packaged using: + ```shell script ./gradlew build ``` -It produces the `theodolite-quarkus-1.0.0-SNAPSHOT-runner.jar` file in the `/build` directory. -Be aware that it’s not an _über-jar_ as the dependencies are copied into the `build/lib` directory. + +It produces the `theodolite-quarkus-1.0.0-SNAPSHOT-runner.jar` file in the `/build` directory. Be aware that it’s not +an _über-jar_ as the dependencies are copied into the `build/lib` directory. If you want to build an _über-jar_, execute the following command: + ```shell script ./gradlew build -Dquarkus.package.type=uber-jar ``` @@ -30,11 +34,13 @@ The application is now runnable using `java -jar build/theodolite-quarkus-1.0.0- ## Creating a native executable You can create a native executable using: + ```shell script ./gradlew build -Dquarkus.package.type=native ``` Or, if you don't have GraalVM installed, you can run the native executable build in a container using: + ```shell script ./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true ``` @@ -44,20 +50,73 @@ You can then execute your native executable with: If you want to learn more about building native executables, please consult https://quarkus.io/guides/gradle-tooling. -# RESTEasy JAX-RS +## Build docker images + +For the jvm version use: + +```shell script +./gradlew build +docker build -f src/main/docker/Dockerfile.jvm -t theodolite-quarkus-jvm . +``` + +For the native image version use: + +```shell script +./gradlew build -Dquarkus.package.type=native +docker build -f src/main/docker/Dockerfile.native -t theodolite-quarkus-native . +``` + +## Execute docker images: -<p>A Hello World RESTEasy resource</p> +Remember to set the environment variables first. -Guide: https://quarkus.io/guides/rest-json +Jvm version: -## Build and afterwards run the application in Docker container +```shell script +docker run -i --rm theodolite-quarkus-jvm +``` + +Native image version: -```build_jvm.sh``` to build the jvm version +```shell script +docker run -i --rm theodolite-quarkus-native +``` -```build_native.sh``` to build the native image graal version +## Environment variables -## Install Detekt Code analysis Plugin +**Production:** (Docker-Container) +| Variables name | Default value |Usage | +| -----------------------------|:----------------------------------:| ------------:| +| `NAMESPACE` | `default` |Determines the namespace of the Theodolite will be executed in. Used in the KubernetesBenchmark| +| `THEODOLITE_EXECUTION` | `./config/BenchmarkExecution.yaml`|The complete path to the benchmarkExecution file. Used in the TheodoliteYamlExecutor. | +| `THEODOLITE_BENCHMARK_TYPE` | `./config/BenchmarkType.yaml` |The complete path to the benchmarkType file. Used in the TheodoliteYamlExecutor.| +| `THEODOLITE_APP_RESOURCES` | `./config` |The path under which the yamls for the resources for the subexperiments are found. Used in the KubernetesBenchmark| +| `MODE` | `yaml-executor` | Defines the mode of operation: either `yaml-executor` or `operator`| + +**Development:** (local via Intellij) + +When running Theodolite from within IntelliJ via +[Run Configurations](https://www.jetbrains.com/help/idea/work-with-gradle-tasks.html#gradle_run_config), set the * +Environment variables* field to: + +``` +NAMESPACE=default;THEODOLITE_BENCHMARK=./../../../../config/BenchmarkType.yaml;THEODOLITE_APP_RESOURCES=./../../../../config;THEODOLITE_EXECUTION=./../../../../config/BenchmarkExecution.yaml;MODE=operator +``` + +Alternative: + +``` sh +export NAMESPACE=default +export THEODOLITE_BENCHMARK=./../../../../config/BenchmarkType.yaml +export THEODOLITE_APP_RESOURCES=./../../../../config +export THEODOLITE_EXECUTION=./../../../../config/BenchmarkExecution.yaml +export MODE=operator +./gradlew quarkusDev + +``` + +#### Install Detekt Code analysis Plugin Install https://plugins.jetbrains.com/plugin/10761-detekt @@ -66,11 +125,10 @@ Install https://plugins.jetbrains.com/plugin/10761-detekt - Check Enable Detekt - Specify your detekt configuration and baseline file (optional) - -> detekt issues will be annotated on-the-fly while coding **ingore Failures in build:** add ```ignoreFailures = true``` - to build.gradle detekt task +to build.gradle detekt task diff --git a/theodolite-quarkus/config/README.md b/theodolite-quarkus/config/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4f53d87ba9ac12099091faa315913cf93ed62bb7 --- /dev/null +++ b/theodolite-quarkus/config/README.md @@ -0,0 +1,194 @@ +## The Benchmark Object + +The *benchmark* object defines all static components of an execution of a benchmark with Theodolite. +An exapmle for a benchmark object is given in [example-benchmark-yaml-resource](example-benchmark-yaml-resource.yaml). + + +A **Benchmark** is a [*standard tool for the competitive evaluation and comparison of competing systems or components according to specific characteristics, such as performance, dependability, or security*](https://doi.org/10.1145/2668930.2688819). In Theodolite, we have [specification-based benchmarks](https://doi.org/10.1145/2668930.2688819), or at least something very close to that. That is, our benchmarks are architectural descriptions---in our case---[of typical use cases of stream processing in microservices](https://doi.org/10.1016/j.bdr.2021.100209) (e.g. our UC1). Hence, we don't really have a piece of software, which represents a benchmark. We only have implementations of benchmarks, e.g. an implementation of UC1 with Kafka Streams. For simplification, we call these *benchmark implementations* simply *benchmarks*. + +```yaml +name: String +appResource: + - String + ... +loadGenResource: + - String + ... +resourceTypes: + - typeName: String + patchers: + - type: String + resources: String + <Patcher Arguments> ... + ... +loadTypes: + - typeName: String + patchers: + - type: String + resources: String + <Patcher Arguments> ... + ... +kafkaConfig: + bootstrapServer: String + topics: + - name: String + numPartitions: UnsignedInt + replicationFactor: UnsignedInt + - name: String + removeOnly: bool + ... +``` + +The properties have the following definitions: + +* **name**: The name of the *benchmark* +* **appResource**: A list of file names that reference Kubernetes resources that are deployed on the cluster for the system under test (SUT). +* **loadGenResources**: A list of file names that reference Kubernetes resources that are deployed on the cluster for the load generator. +* **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* object. Each resource type has the following structure: + * **typeName**: Name of the resource type. + * **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. +* **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: + * **typeName**: Name of the resource type. + * **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. +* **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. + * **name**: The name of the topic. + * **numPartitions**: The number of partitions of the topic. + * **replicationFactor**: The replication factor of the topic. + * **removeOnly**: determines if this topic should only be deleted after each experiement. For removeOnly topics the name can be a RegEx describing the topic. + + +## The Execution Object + +A benchmark can be executed for different SUTs, by different users and multiple times. We call such an execution of a benchmark simply an *execution*. The *execution* object defines all conrete values of an Execution. +An exapmle for an execution object is given in [example-execution-yaml-resource](example-benchmark-yaml-resource.yaml). + + +```yaml +name: String +benchmark: String +load: + loadType: String + loadValues: + - UnsignedInt + ... +resources: + resourceType: String + resourceValues: + - UnsignedInt + ... +slos: + - sloType: String + threshold: UnsignedInt + prometheusUrl: String + externalSloUrl: String + offset: SignedInt + warmup: UnsignedInt + ... +executions: + strategy: "LinearSearch" or "BinarySearch" + duration: UnsignedInt + repetition: UnsignedInt + restrictions: + - "LowerBound" + ... +configurationOverrides: + - patcher: + type: String + resource: String + <Patcher Arguments> ... + ... +``` + +The properties have the following definitions: + +* **name**: The name of the *execution* +* **benchmark**: The name of the *benchmark* this *execution* is referring to. +* **load**: Specifies the load values that are benchmarked. + * **loadType**: The type of the load. It must match one of the load types specified in the referenced *benchmark*. + * **loadValues**: List of load values for the specified load type. +* **resources**: Specifies the scaling resource that is benchmarked. + * **resourceType**: The type of the resource. It must match one of the resource types specified in the referenced *benchmark*. + * **resourceValues**: List of resource values for the specified resource type. +* **slos**: List of the Service Level Objective (SLO) for this *execution*. Each SLO has the following fields: + * **sloType**: The type of the SLO. It must match 'lag trend'. + * **threshold**: The threshold the SUT should meet for a sucessful experiment. + * **prometheusUrl**: Connection string for promehteus. + * **externalSloUrl**: Connection string for a external slo analysis. + * **offset**: Hours by which the start and end timestamp will be shifted (for different timezones). + * **warmup**: Seconds of time that are ignored in the analysis. +* **executions**: Defines the overall parameter for the execution. + * **strategy**: Defines the used strategy for the execution: either 'LinearSearch' or 'BinarySearch' + * **duration**: Defines the duration of each [experiment](#Experiment) in seconds. + * **repetition**: Unused. + * **restrictions**: List of restriction strategys used to delimit the search space. + **- LowerBound**: Currently only supported *restriction strategy*. +* **configurationOverrides**: List of patchers that are used to override existing configurations. + * **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. + +## Patchers + +* **ReplicaPatcher**: Allows to modify the number of Replicas for a kubernetes deployment. + * **type**: "ReplicaPatcher" + * **resource**: "uc1-kstreams-deployment.yaml" + +* **NumSensorsLoadGeneratorReplicaPatcher**: Allows to scale the nummer of load generators. Scales arcording to the following formular: (value + 15_000 - 1) / 15_000 + * **type**: "NumSensorsLoadGeneratorReplicaPatcher" + * **resource**: "uc1-load-generator-deployment.yaml" + +* **NumNestedGroupsLoadGeneratorReplicaPatcher**: Allows to scale the nummer of load generators. Scales arcording to the following formular: (4^(value) + 15_000 -1) /15_000 + * **type**: "NumNestedGroupsLoadGeneratorReplicaPatcher" + * **resource**: "uc1-load-generator-deployment.yaml" + +* **ReplicaPatcher**: Allows to modify the number of Replicas for a kubernetes deployment. + * **type**: "ReplicaPatcher" + * **resource**: "uc1-kstreams-deployment.yaml" + +* **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" + +* **NodeSelectorPatcher**: Changes the node selection field in kubernetes resources. + * **type**: "NodeSelectorPatcher" + * **resource**: "uc1-load-generator-deployment.yaml" + * **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" + * **value**:"1000m" or "2Gi" + +* **SchedulerNamePatcher**: Changes the sheduler for kubernetes resources. + * **type**: "SchedulerNamePatcher" + * **resource**: "uc1-kstreams-deployment.yaml" + * **value**: "random-scheduler" + +* **ImagePatcher**: Changes the image of a kubernetes resource. Currently not fully implemented. + * **type**: "ImagePatcher" + * **resource**: "uc1-kstreams-deployment.yaml" + * **container**: "uc-application" + * **value**: "dockerhubrepo/imagename" + + + +## Experiment +According to [our benchmarking method](https://doi.org/10.1016/j.bdr.2021.100209), the execution of a benchmark requires performing multiple **Experiments**. I think what is actually done within/during an experiment is another level of detail. (But just for the sake of completeness: In an experiment, the benchmark implementation is deployed, load is generated according to the benchmark specification, some SLOs are monitored continuously, etc.) + + + diff --git a/theodolite-quarkus/examples/operator/example-execution.yaml b/theodolite-quarkus/examples/operator/example-execution.yaml index ef625dfe6ec78c2cc0ed099dfee0f767d57263bb..7f76b1bca0db77df08861e0611487642e19bbc1a 100644 --- a/theodolite-quarkus/examples/operator/example-execution.yaml +++ b/theodolite-quarkus/examples/operator/example-execution.yaml @@ -22,6 +22,7 @@ execution: strategy: "LinearSearch" duration: 60 repetitions: 1 + delay: 30 # in seconds restrictions: - "LowerBound" configOverrides: diff --git a/theodolite-quarkus/examples/standalone/example-benchmark.yaml b/theodolite-quarkus/examples/standalone/example-benchmark.yaml index ebc2fe9e44fe303e342cabee301cb63664867cfb..cdc2122d9e6b568f1a75b0d55eff8a0af6450983 100644 --- a/theodolite-quarkus/examples/standalone/example-benchmark.yaml +++ b/theodolite-quarkus/examples/standalone/example-benchmark.yaml @@ -22,7 +22,7 @@ loadTypes: - type: "NumSensorsLoadGeneratorReplicaPatcher" resource: "uc1-load-generator-deployment.yaml" kafkaConfig: - bootstrapServer: "theodolite-cp-kafka:9092" + bootstrapServer: "localhost:31290" topics: - name: "input" numPartitions: 40 diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt index db7999b205c61d94fa17791a5d549a2620601b6b..05d021b1bcfb77fa8ffeb0522510d49e39ef501c 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt @@ -21,6 +21,8 @@ interface Benchmark { fun buildDeployment( load: LoadDimension, res: Resource, - configurationOverrides: List<ConfigurationOverride?> + configurationOverrides: List<ConfigurationOverride?>, + loadGenerationDelay: Long, + afterTeardownDelay: Long ): BenchmarkDeployment } diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt index 2d5d15b3389cf723be3a8ceb0fff8b27bd700419..38d0f0389ce92a8720df05e892d11cf4f1ac480a 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt @@ -47,6 +47,8 @@ class BenchmarkExecution : CustomResource(), Namespaced { var duration by Delegates.notNull<Long>() var repetitions by Delegates.notNull<Int>() lateinit var restrictions: List<String> + var loadGenerationDelay = 0L + var afterTeardownDelay = 5L } /** diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt index bbcb8a957fb2f04ca678b231a878be0a23d46748..c89e9e85323d6e51c104b1d34ff1ef9d8d4d60cd 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt @@ -22,7 +22,7 @@ private var DEFAULT_NAMESPACE = "default" * - [loadGenResource] resource that generates the load, * - [resourceTypes] types of scaling resources, * - [loadTypes] types of loads that can be scaled for the benchmark, - * - [kafkaConfig] for the [TopicManager], + * - [kafkaConfig] for the [theodolite.k8s.TopicManager], * - [namespace] for the client, * - [path] under which the resource yamls can be found. * @@ -63,38 +63,45 @@ class KubernetesBenchmark : Benchmark, CustomResource(), Namespaced { * First loads all required resources and then patches them to the concrete load and resources for the experiment. * Afterwards patches additional configurations(cluster depending) into the resources. * @param load concrete load that will be benchmarked in this experiment. - * @param res concrete resoruce that will be scaled for this experiment. + * @param res concrete resource that will be scaled for this experiment. * @param configurationOverrides * @return a [BenchmarkDeployment] */ override fun buildDeployment( load: LoadDimension, res: Resource, - configurationOverrides: List<ConfigurationOverride?> + configurationOverrides: List<ConfigurationOverride?>, + loadGenerationDelay: Long, + afterTeardownDelay: Long ): BenchmarkDeployment { logger.info { "Using $namespace as namespace." } logger.info { "Using $path as resource path." } - val resources = loadKubernetesResources(this.appResource + this.loadGenResource) + val appResources = loadKubernetesResources(this.appResource) + val loadGenResources = loadKubernetesResources(this.loadGenResource) + val patcherFactory = PatcherFactory() // patch the load dimension the resources load.getType().forEach { patcherDefinition -> - patcherFactory.createPatcher(patcherDefinition, resources).patch(load.get().toString()) + patcherFactory.createPatcher(patcherDefinition, loadGenResources).patch(load.get().toString()) } res.getType().forEach { patcherDefinition -> - patcherFactory.createPatcher(patcherDefinition, resources).patch(res.get().toString()) + patcherFactory.createPatcher(patcherDefinition, appResources).patch(res.get().toString()) } // Patch the given overrides configurationOverrides.forEach { override -> override?.let { - patcherFactory.createPatcher(it.patcher, resources).patch(override.value) + patcherFactory.createPatcher(it.patcher, appResources + loadGenResources).patch(override.value) } } return KubernetesBenchmarkDeployment( namespace = namespace, - resources = resources.map { r -> r.second }, + appResources = appResources.map { it.second }, + loadGenResources = loadGenResources.map { it.second }, + loadGenerationDelay = loadGenerationDelay, + afterTeardownDelay = afterTeardownDelay, kafkaConfig = hashMapOf("bootstrap.servers" to kafkaConfig.bootstrapServer), topics = kafkaConfig.topics, client = DefaultKubernetesClient().inNamespace(namespace) diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt index a6bf881d6ded7b0936b400a37b572c77c95bb241..6cf239676ddb24752f4754a85fc62657f9eb6603 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt @@ -8,6 +8,7 @@ import org.apache.kafka.clients.admin.NewTopic import theodolite.k8s.K8sManager import theodolite.k8s.TopicManager import theodolite.util.KafkaConfig +import java.time.Duration private val logger = KotlinLogging.logger {} @@ -22,7 +23,10 @@ private val logger = KotlinLogging.logger {} @RegisterForReflection class KubernetesBenchmarkDeployment( val namespace: String, - val resources: List<KubernetesResource>, + val appResources: List<KubernetesResource>, + val loadGenResources: List<KubernetesResource>, + private val loadGenerationDelay: Long, + private val afterTeardownDelay: Long, private val kafkaConfig: HashMap<String, Any>, private val topics: List<KafkaConfig.TopicWrapper>, private val client: NamespacedKubernetesClient @@ -30,7 +34,6 @@ class KubernetesBenchmarkDeployment( private val kafkaController = TopicManager(this.kafkaConfig) private val kubernetesManager = K8sManager(client) private val LAG_EXPORTER_POD_LABEL = "app.kubernetes.io/name=kafka-lag-exporter" - private val SLEEP_AFTER_TEARDOWN = 5000L /** * Setup a [KubernetesBenchmark] using the [TopicManager] and the [K8sManager]: @@ -39,9 +42,12 @@ class KubernetesBenchmarkDeployment( */ override fun setup() { val kafkaTopics = this.topics.filter { !it.removeOnly } - .map{ NewTopic(it.name, it.numPartitions, it.replicationFactor) } + .map { NewTopic(it.name, it.numPartitions, it.replicationFactor) } kafkaController.createTopics(kafkaTopics) - resources.forEach { kubernetesManager.deploy(it) } + appResources.forEach { kubernetesManager.deploy(it) } + logger.info { "Wait ${this.loadGenerationDelay} seconds before starting the load generator." } + Thread.sleep(Duration.ofSeconds(this.loadGenerationDelay).toMillis()) + loadGenResources.forEach { kubernetesManager.deploy(it) } } /** @@ -51,12 +57,11 @@ class KubernetesBenchmarkDeployment( * - Remove the [KubernetesResource]s. */ override fun teardown() { - resources.forEach { - kubernetesManager.remove(it) - } + loadGenResources.forEach { kubernetesManager.remove(it) } + appResources.forEach { kubernetesManager.remove(it) } kafkaController.removeTopics(this.topics.map { topic -> topic.name }) KafkaLagExporterRemover(client).remove(LAG_EXPORTER_POD_LABEL) - logger.info { "Teardown complete. Wait $SLEEP_AFTER_TEARDOWN ms to let everything come down." } - Thread.sleep(SLEEP_AFTER_TEARDOWN) + logger.info { "Teardown complete. Wait $afterTeardownDelay ms to let everything come down." } + Thread.sleep(Duration.ofSeconds(afterTeardownDelay).toMillis()) } } diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt index 94d816d87923f4d8343c6c83dd9747f1cc25ff81..758dcdefcaee79654d8ff65f0f798832aafc1294 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt @@ -4,7 +4,7 @@ import theodolite.util.PrometheusResponse import java.time.Instant /** - * A SloChecker can be used to evaluate data from Promehteus. + * A SloChecker can be used to evaluate data from Prometheus. * @constructor Creates an empty SloChecker */ interface SloChecker { diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt index 6d4cd9ea9b5d03dda360b2ddcefcfb9682fd8383..494e52878ce6bfe5f7ad57ebf4c9030db5a66a55 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt @@ -24,9 +24,11 @@ abstract class BenchmarkExecutor( val benchmark: Benchmark, val results: Results, val executionDuration: Duration, - configurationOverrides: List<ConfigurationOverride?>, + val configurationOverrides: List<ConfigurationOverride?>, val slo: BenchmarkExecution.Slo, - val executionId: Int + val executionId: Int, + val loadGenerationDelay: Long, + val afterTeardownDelay: Long ) { var run: AtomicBoolean = AtomicBoolean(true) @@ -41,7 +43,7 @@ abstract class BenchmarkExecutor( * given load, false otherwise. */ abstract fun runExperiment(load: LoadDimension, res: Resource): Boolean - + /** * Wait while the benchmark is running and log the number of minutes executed every 1 minute. * diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt index cd85c143e3c416f115a4d301629caf4d46b7459f..6237af7fc78b03d3dca5941f1d8f9d9b9ea58246 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt @@ -18,13 +18,15 @@ class BenchmarkExecutorImpl( benchmark: Benchmark, results: Results, executionDuration: Duration, - private val configurationOverrides: List<ConfigurationOverride?>, + configurationOverrides: List<ConfigurationOverride?>, slo: BenchmarkExecution.Slo, - executionId: Int -) : BenchmarkExecutor(benchmark, results, executionDuration, configurationOverrides, slo, executionId) { + executionId: Int, + loadGenerationDelay: Long, + afterTeardownDelay: Long +) : BenchmarkExecutor(benchmark, results, executionDuration, configurationOverrides, slo, executionId, loadGenerationDelay, afterTeardownDelay) { override fun runExperiment(load: LoadDimension, res: Resource): Boolean { var result = false - val benchmarkDeployment = benchmark.buildDeployment(load, res, this.configurationOverrides) + val benchmarkDeployment = benchmark.buildDeployment(load, res, configurationOverrides, loadGenerationDelay, this.afterTeardownDelay) try { benchmarkDeployment.setup() diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/Main.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/Main.kt index 64a40c0b11854d61900ab1fde3797e17427cac15..bf883529967a8b24229fe8256ba0e4edd11b342c 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/Main.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/Main.kt @@ -16,14 +16,14 @@ object Main { val mode = System.getenv("MODE") ?: "standalone" logger.info { "Start Theodolite with mode $mode" } - when(mode) { + when (mode) { "standalone" -> TheodoliteYamlExecutor().start() "yaml-executor" -> TheodoliteYamlExecutor().start() // TODO remove (#209) "operator" -> TheodoliteOperator().start() - else -> { + else -> { logger.error { "MODE $mode not found" } exitProcess(1) } } } -} \ No newline at end of file +} diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt index a50a38e79b52a72fa68eb9eda70cf1072f80df74..0ff8379a0af4b11154214dde021d7c60609631d1 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt @@ -30,7 +30,9 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b benchmark.buildDeployment( load = LoadDimension(0, emptyList()), res = Resource(0, emptyList()), - configurationOverrides = benchmarkExecution.configOverrides + configurationOverrides = benchmarkExecution.configOverrides, + loadGenerationDelay = 0L, + afterTeardownDelay = 5L ) deployment.teardown() } catch (e: Exception) { diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt index 5fd2eedecdc42b575d69760025a31f45eb71fec0..34fbc2f8a3cc5934f8d49c6ebac053fbd91e5551 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt @@ -71,7 +71,9 @@ class TheodoliteExecutor( executionDuration = executionDuration, configurationOverrides = config.configOverrides, slo = config.slos[0], - executionId = config.executionId + executionId = config.executionId, + loadGenerationDelay = config.execution.loadGenerationDelay, + afterTeardownDelay = config.execution.afterTeardownDelay ) return Config( @@ -128,7 +130,7 @@ class TheodoliteExecutor( fun run() { val resultsFolder = getResultFolderString() storeAsFile(this.config, "$resultsFolder${this.config.executionId}-execution-configuration") - storeAsFile(kubernetesBenchmark, "$resultsFolder/${this.config.executionId}-benchmark-configuration") + storeAsFile(kubernetesBenchmark, "$resultsFolder${this.config.executionId}-benchmark-configuration") val config = buildConfig() // execute benchmarks for each load diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/BenchmarkEventHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/BenchmarkEventHandler.kt index 69c53a3792d86d0ad1c3e973b1d53ea5defff8d9..7c8188e3c342cfc1b22fefdd3ca91e7dbce85905 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/BenchmarkEventHandler.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/BenchmarkEventHandler.kt @@ -3,6 +3,7 @@ package theodolite.execution.operator import io.fabric8.kubernetes.client.informers.ResourceEventHandler import mu.KotlinLogging import theodolite.benchmark.KubernetesBenchmark + private val logger = KotlinLogging.logger {} /** @@ -13,7 +14,7 @@ private val logger = KotlinLogging.logger {} * @see TheodoliteController * @see KubernetesBenchmark */ -class BenchmarkEventHandler(private val controller: TheodoliteController): ResourceEventHandler<KubernetesBenchmark> { +class BenchmarkEventHandler(private val controller: TheodoliteController) : ResourceEventHandler<KubernetesBenchmark> { /** * Add a KubernetesBenchmark. @@ -39,7 +40,7 @@ class BenchmarkEventHandler(private val controller: TheodoliteController): Resou override fun onUpdate(oldBenchmark: KubernetesBenchmark, newBenchmark: KubernetesBenchmark) { logger.info { "Update benchmark ${newBenchmark.metadata.name}." } newBenchmark.name = newBenchmark.metadata.name - if (this.controller.isInitialized() && this.controller.executor.getBenchmark().name == oldBenchmark.metadata.name) { + if (this.controller.isInitialized() && this.controller.executor.getBenchmark().name == oldBenchmark.metadata.name) { this.controller.isUpdated.set(true) this.controller.executor.executor.run.compareAndSet(true, false) } else { @@ -57,7 +58,7 @@ class BenchmarkEventHandler(private val controller: TheodoliteController): Resou override fun onDelete(benchmark: KubernetesBenchmark, b: Boolean) { logger.info { "Delete benchmark ${benchmark.metadata.name}." } this.controller.benchmarks.remove(benchmark.metadata.name) - if ( this.controller.isInitialized() && this.controller.executor.getBenchmark().name == benchmark.metadata.name) { + if (this.controller.isInitialized() && this.controller.executor.getBenchmark().name == benchmark.metadata.name) { this.controller.isUpdated.set(true) this.controller.executor.executor.run.compareAndSet(true, false) logger.info { "Current benchmark stopped." } diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt index 971d3428ffde9cf776711bbd68bae68f66597823..ea62b7b895fce772a1f89019ea4aaac0f3957dc1 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt @@ -3,7 +3,6 @@ package theodolite.execution.operator import io.fabric8.kubernetes.client.informers.ResourceEventHandler import mu.KotlinLogging import theodolite.benchmark.BenchmarkExecution -import java.lang.NullPointerException private val logger = KotlinLogging.logger {} @@ -15,7 +14,7 @@ private val logger = KotlinLogging.logger {} * @see TheodoliteController * @see BenchmarkExecution */ -class ExecutionHandler(private val controller: TheodoliteController): ResourceEventHandler<BenchmarkExecution> { +class ExecutionHandler(private val controller: TheodoliteController) : ResourceEventHandler<BenchmarkExecution> { /** * Add an execution to the end of the queue of the TheodoliteController. @@ -29,17 +28,19 @@ class ExecutionHandler(private val controller: TheodoliteController): ResourceEv } /** - * Update an execution. If this execution is running at the time this function is called, it is stopped and added to - * the beginning of the queue of the TheodoliteController. Otherwise, it is just added to the beginning of the queue. + * Updates an execution. If this execution is running at the time this function is called, it is stopped and + * added to the beginning of the queue of the TheodoliteController. + * Otherwise, it is just added to the beginning of the queue. * - * @param execution the execution to update + * @param oldExecution the old execution + * @param newExecution the new execution */ override fun onUpdate(oldExecution: BenchmarkExecution, newExecution: BenchmarkExecution) { logger.info { "Add updated execution to queue." } newExecution.name = newExecution.metadata.name try { this.controller.executionsQueue.removeIf { e -> e.name == newExecution.metadata.name } - } catch(e: NullPointerException) { + } catch (e: NullPointerException) { logger.warn { "No execution found for deletion" } } this.controller.executionsQueue.addFirst(newExecution) @@ -58,7 +59,7 @@ class ExecutionHandler(private val controller: TheodoliteController): ResourceEv try { this.controller.executionsQueue.removeIf { e -> e.name == execution.metadata.name } logger.info { "Delete execution ${execution.metadata.name} from queue." } - } catch(e: NullPointerException) { + } catch (e: NullPointerException) { logger.warn { "No execution found for deletion" } } if (this.controller.isInitialized() && this.controller.executor.getExecution().name == execution.metadata.name) { 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 532185841a7a8ee000722c1dc513219177f00cae..0e889e0393e17fd65f4d8f12c5b95a3dbed7f593 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt @@ -2,7 +2,6 @@ package theodolite.execution.operator import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext -import khttp.patch import mu.KotlinLogging import theodolite.benchmark.BenchmarkExecution import theodolite.benchmark.KubernetesBenchmark diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sContextFactory.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sContextFactory.kt index c0e07610171b40c6704602ffa86ec15accb14c19..7eb209bfbab02bb94d34c985aa308173e509d4e4 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sContextFactory.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sContextFactory.kt @@ -21,12 +21,12 @@ class K8sContextFactory { * * @see CustomResourceDefinitionContext */ - fun create(api: String, scope: String, group: String, plural: String ) : CustomResourceDefinitionContext { - return CustomResourceDefinitionContext.Builder() + fun create(api: String, scope: String, group: String, plural: String): CustomResourceDefinitionContext { + return CustomResourceDefinitionContext.Builder() .withVersion(api) .withScope(scope) .withGroup(group) .withPlural(plural) .build() } -} \ No newline at end of file +} diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt index 324b02b74b2c53eb1292667f037f3fdbcc114b73..fd5ec3b2e744b5e096187626a2fd756f71f87e67 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt @@ -32,7 +32,14 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) { * @return CustomResource from fabric8 */ private fun loadServiceMonitor(path: String): ServiceMonitorWrapper { - return loadGenericResource(path) { x: String -> ServiceMonitorWrapper(YamlParser().parse(path, HashMap<String, String>()::class.java)!!) } + return loadGenericResource(path) { x: String -> + ServiceMonitorWrapper( + YamlParser().parse( + path, + HashMap<String, String>()::class.java + )!! + ) + } } /** diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/TopicManager.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/TopicManager.kt index ef5715e248ae6c64df0035a94d57fea12202787e..3bbae82d77dc5b01a5827c7ee713bf2566be1bab 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/TopicManager.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/TopicManager.kt @@ -45,7 +45,7 @@ class TopicManager(private val kafkaConfig: Map<String, Any>) { "Topics creation finished with result: ${ result .values() - .map { it -> it.key + ": " + it.value.isDone } + .map { it.key + ": " + it.value.isDone } .joinToString(separator = ",") } " } @@ -59,16 +59,17 @@ class TopicManager(private val kafkaConfig: Map<String, Any>) { fun removeTopics(topics: List<String>) { val kafkaAdmin: AdminClient = AdminClient.create(this.kafkaConfig) val currentTopics = kafkaAdmin.listTopics().names().get() - delete(currentTopics.filter{ matchRegex(it, topics) }, kafkaAdmin) + delete(currentTopics.filter { matchRegex(it, topics) }, kafkaAdmin) kafkaAdmin.close() } /** - * This function checks whether one string in `topics` can be used as prefix of a regular expression to create the string `existingTopic` + * This function checks whether one string in `topics` can be used as prefix of a regular expression + * to create the string `existingTopic`. * - * @param existingTopic string for which should be checked if it could be created - * @param topics list of string which are used as possible prefixes to create `existingTopic` - * @return true, `existingTopics` matches a created regex, else false + * @param existingTopic string for which should be checked if it could be created. + * @param topics list of string which are used as possible prefixes to create `existingTopic`. + * @return true, `existingTopics` matches a created regex, else false. */ private fun matchRegex(existingTopic: String, topics: List<String>): Boolean { for (t in topics) { @@ -89,7 +90,7 @@ class TopicManager(private val kafkaConfig: Map<String, Any>) { result.all().get() // wait for the future to be completed logger.info { "Topics deletion finished with result: ${ - result.values().map { it -> it.key + ": " + it.value.isDone } + result.values().map { it.key + ": " + it.value.isDone } .joinToString(separator = ",") }" } diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt index e5e5f6cb67641c71ad0fd31375752cbb03fa62db..b29d8d9925311aa25b7336dcd6805783ca62c3e7 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt @@ -12,7 +12,7 @@ import io.fabric8.kubernetes.api.model.apps.StatefulSet */ class ImagePatcher(private val k8sResource: KubernetesResource, private val container: String) : AbstractPatcher(k8sResource, container) { - + override fun <String> patch(imagePath: String) { if (k8sResource is Deployment) { k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach { diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt index 7cf56f8452949e387a186aa8f8c962e1ee1aad15..d7136740a7e17f956eed16bc6e3fcd4954ab91b8 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt @@ -7,12 +7,13 @@ 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) : AbstractPatcher(k8sResource) { +class NumNestedGroupsLoadGeneratorReplicaPatcher(private val k8sResource: KubernetesResource) : + 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 loadGenInstances = (approxNumSensors + LOAD_GEN_MAX_RECORDS - 1) / LOAD_GEN_MAX_RECORDS 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 6f2ebcb8b1eb37801c7f6bb2f28c251a07ae44e8..d29280a648cd4c912b8e2717b51c4f9c3f8a2271 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt @@ -5,7 +5,8 @@ import io.fabric8.kubernetes.api.model.apps.Deployment private const val LOAD_GEN_MAX_RECORDS = 150000 -class NumSensorsLoadGeneratorReplicaPatcher(private val k8sResource: KubernetesResource) : AbstractPatcher(k8sResource) { +class NumSensorsLoadGeneratorReplicaPatcher(private val k8sResource: KubernetesResource) : + AbstractPatcher(k8sResource) { override fun <String> patch(value: String) { if (k8sResource is Deployment) { if (value is kotlin.String) { diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt index eab82effbc084e91ba57c1bea7103b2a3239c922..30f82e804f23b770457ec968f25ba7c00d72aefd 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt @@ -6,7 +6,6 @@ import io.fabric8.kubernetes.api.model.Quantity import io.fabric8.kubernetes.api.model.ResourceRequirements import io.fabric8.kubernetes.api.model.apps.Deployment import io.fabric8.kubernetes.api.model.apps.StatefulSet -import java.lang.IllegalArgumentException /** * The Resource limit [Patcher] set resource limits for deployments and statefulSets. diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt index f4ef38edebab67022066394e149716ab9ffbce00..24b2a6d40525f16448b77c50fba8aba0969d075a 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt @@ -6,7 +6,6 @@ import io.fabric8.kubernetes.api.model.Quantity import io.fabric8.kubernetes.api.model.ResourceRequirements import io.fabric8.kubernetes.api.model.apps.Deployment import io.fabric8.kubernetes.api.model.apps.StatefulSet -import java.lang.IllegalArgumentException /** * The Resource request [Patcher] set resource limits for deployments and statefulSets. diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt index 589bceff78158a422d923169bd35a1e11e2f4caa..348f0c50090a34c91221d3e099c3532375a578da 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt @@ -4,14 +4,14 @@ import io.fabric8.kubernetes.api.model.KubernetesResource import io.fabric8.kubernetes.api.model.apps.Deployment /** - * The Scheduler name [Patcher] make it possible to set the scheduler which should be used to deploy the given deployment. - * + * The Scheduler name [Patcher] make it possible to set the scheduler which should + * be used to deploy the given deployment. * @param k8sResource Kubernetes resource to be patched. */ -class SchedulerNamePatcher(private val k8sResource: KubernetesResource): Patcher { +class SchedulerNamePatcher(private val k8sResource: KubernetesResource) : Patcher { override fun <String> patch(value: String) { if (k8sResource is Deployment) { k8sResource.spec.template.spec.schedulerName = value as kotlin.String } } -} \ No newline at end of file +} diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/CompositeStrategy.kt b/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/CompositeStrategy.kt index 6ae06d70c9effe0a0a4bbd9abffa665fb08636c9..41cc5c325163ade54469398e815fdb8d95c6e6cd 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/CompositeStrategy.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/CompositeStrategy.kt @@ -10,7 +10,7 @@ import theodolite.util.Resource * Composite strategy that combines a SearchStrategy and a set of RestrictionStrategy. * * @param searchStrategy the [SearchStrategy] that is executed as part of this [CompositeStrategy]. - * @param restrictionStrategies the set of [RestrictionStrategy] that are connected conjuntively to restrict the [Resource] + * @param restrictionStrategies the set of [RestrictionStrategy] that are connected conjunctive to restrict the [Resource] * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks. */ @RegisterForReflection diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt b/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt index 20290a9477f16c7d479d32ec4435da0c1bb26514..cb0dd2d8ab528e42e8290f59f26c8b9b32f384c7 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt @@ -18,7 +18,7 @@ private val logger = KotlinLogging.logger {} class FullSearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) { override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? { - var minimalSuitableResources: Resource? = null; + var minimalSuitableResources: Resource? = null for (res in resources) { logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" } val result = this.benchmarkExecutor.runExperiment(load, res) diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt index f304d8cd06969d4650329b9b9f410a56985a2002..398ff90bed8f48683321e2375458b3a065c39463 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt @@ -2,7 +2,7 @@ package theodolite.util import com.fasterxml.jackson.databind.annotation.JsonDeserialize import io.quarkus.runtime.annotations.RegisterForReflection -import org.apache.kafka.clients.admin.NewTopic +import theodolite.util.KafkaConfig.TopicWrapper import kotlin.properties.Delegates import kotlin.reflect.KProperty @@ -60,6 +60,7 @@ class DelegatesFalse { operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean { return state } + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) { state = value } diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt index 7802529bfda309131cafc0ab3f39fda43285c32f..c2b30ab7eb23d60db39778218ad9d6a4c12799a6 100644 --- a/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt +++ b/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt @@ -31,7 +31,7 @@ class CompositeStrategyTest { val results = Results() val benchmark = TestBenchmark() val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo() - val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0) + val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0, 5) val linearSearch = LinearSearch(benchmarkExecutor) val lowerBoundRestriction = LowerBoundRestriction(results) val strategy = @@ -65,7 +65,7 @@ class CompositeStrategyTest { val benchmark = TestBenchmark() val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo() val benchmarkExecutorImpl = - TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0) + TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0, 0) val binarySearch = BinarySearch(benchmarkExecutorImpl) val lowerBoundRestriction = LowerBoundRestriction(results) val strategy = @@ -98,7 +98,7 @@ class CompositeStrategyTest { val results = Results() val benchmark = TestBenchmark() val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo() - val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0) + val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0,0) val binarySearch = BinarySearch(benchmarkExecutor) val lowerBoundRestriction = LowerBoundRestriction(results) val strategy = diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt index 6f476278d08eacfc9857c1e5431636e5a219f26c..6ddca296acced658609fcccb307a83047238e118 100644 --- a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt +++ b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt @@ -11,7 +11,9 @@ class TestBenchmark : Benchmark { override fun buildDeployment( load: LoadDimension, res: Resource, - configurationOverrides: List<ConfigurationOverride?> + configurationOverrides: List<ConfigurationOverride?>, + loadGenerationDelay: Long, + afterTeardownDelay: Long ): BenchmarkDeployment { return TestBenchmarkDeployment() } diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt index 2bafcb76dfc3463d9aa350b88c9f73d52cea6629..91c312261bda83923d068b7dfce67e36afd0ebfb 100644 --- a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt +++ b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt @@ -13,7 +13,9 @@ class TestBenchmarkExecutorImpl( benchmark: Benchmark, results: Results, slo: BenchmarkExecution.Slo, - executionId: Int + executionId: Int, + loadGenerationDelay: Long, + afterTeardownDelay: Long ) : BenchmarkExecutor( benchmark, @@ -21,7 +23,9 @@ class TestBenchmarkExecutorImpl( executionDuration = Duration.ofSeconds(1), configurationOverrides = emptyList(), slo = slo, - executionId = executionId + executionId = executionId, + loadGenerationDelay = loadGenerationDelay, + afterTeardownDelay = afterTeardownDelay ) { override fun runExperiment(load: LoadDimension, res: Resource): Boolean { diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt index b6b9eaecd9fc35b25b9447611835c3d8469cea0e..b368647e314a4d803b444268c8218aefbee00ad4 100644 --- a/theodolite-quarkus/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt +++ b/theodolite-quarkus/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt @@ -1,6 +1,7 @@ package theodolite.strategies.restriction -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import theodolite.util.LoadDimension @@ -41,7 +42,7 @@ internal class LowerBoundRestrictionTest { val restriction = strategy.apply(load, resources) assertEquals(2, restriction.size) - assertEquals(resources.subList(1,3), restriction) + assertEquals(resources.subList(1, 3), restriction) } @Test @@ -111,6 +112,7 @@ internal class LowerBoundRestrictionTest { buildLoadDimension(load), buildResourcesDimension(resources) ), - successful) + successful + ) } -} \ No newline at end of file +}