diff --git a/docs/patchers.md b/docs/patchers.md
new file mode 100644
index 0000000000000000000000000000000000000000..572f107fb38ba295cd013abeff5dd53c2702527b
--- /dev/null
+++ b/docs/patchers.md
@@ -0,0 +1,50 @@
+## 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"
+ * **properties**:
+ * container: "workload-generator"
+ * variableName: "NUM_SENSORS"
+
+* **NodeSelectorPatcher**: Changes the node selection field in kubernetes resources.
+ * **type**: "NodeSelectorPatcher"
+ * **resource**: "uc1-load-generator-deployment.yaml"
+ * **properties**:
+ * variableName: "env"
+ * **value**: "prod"
+
+* **ResourceLimitPatcher**: Changes the resource limit for a kubernetes resource.
+ * **resource**: "uc1-kstreams-deployment.yaml"
+ * **properties**:
+ * 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"
+ * **properties**:
+ * container: "uc-application"
+ * **value**: "dockerhubrepo/imagename"
diff --git a/execution/.dockerignore b/execution/.dockerignore
deleted file mode 100644
index 68e5f21c503a80d7db64722d700351a303ddb9dd..0000000000000000000000000000000000000000
--- a/execution/.dockerignore
+++ /dev/null
@@ -1,9 +0,0 @@
-*
-!requirements.txt
-!uc-workload-generator
-!uc-application
-!strategies
-!lib
-!theodolite.py
-!run_uc.py
-!lag_analysis.py
diff --git a/execution/theodolite.yaml b/execution/theodolite.yaml
index 749c94b12736b2d8546fa3cb46559ec1b4ea0f27..ae18a68ee61c71e20008a71537357cdf9521216a 100644
--- a/execution/theodolite.yaml
+++ b/execution/theodolite.yaml
@@ -25,11 +25,11 @@ spec:
# - name: MODE
# value: yaml-executor # Default is `yaml-executor`
- name: THEODOLITE_EXECUTION
- value: /etc/execution/example-execution-yaml-resource.yaml # The name of this file must correspond to the filename of the execution, from which the config map is created.
+ value: "execution/execution.yaml" # The name of this file must correspond to the filename of the execution, from which the config map is created.
- name: THEODOLITE_BENCHMARK
- value: /etc/benchmark/example-benchmark-yaml-resource.yaml # The name of this file must correspond to the filename of the benchmark, from which the config map is created.
+ value: "benchmark/benchmark.yaml" # The name of this file must correspond to the filename of the benchmark, from which the config map is created.
- name: THEODOLITE_APP_RESOURCES
- value: /etc/app-resources
+ value: "benchmark-resources"
- name: RESULTS_FOLDER # Folder for saving results
value: results # Default is the pwd (/deployments)
# - name: CREATE_RESULTS_FOLDER # Specify whether the specified result folder should be created if it does not exist.
@@ -37,11 +37,11 @@ spec:
volumeMounts:
- mountPath: "/deployments/results" # the mounted path must corresponds to the value of `RESULT_FOLDER`.
name: theodolite-pv-storage
- - mountPath: "/etc/app-resources" # must be corresponds to the value of `THEODOLITE_APP_RESOURCES`.
- name: app-resources
- - mountPath: "/etc/benchmark" # must be corresponds to the value of `THEODOLITE_BENCHMARK`.
+ - mountPath: "/deployments/benchmark-resources" # must correspond to the value of `THEODOLITE_APP_RESOURCES`.
+ name: benchmark-resources
+ - mountPath: "/deployments/benchmark" # must correspond to the value of `THEODOLITE_BENCHMARK`.
name: benchmark
- - mountPath: "/etc/execution" # must be corresponds to the value of `THEODOLITE_EXECUTION`.
+ - mountPath: "/deployments/execution" # must correspond to the value of `THEODOLITE_EXECUTION`.
name: execution
restartPolicy: Never
# Uncomment if RBAC is enabled and configured
@@ -52,9 +52,9 @@ spec:
- name: theodolite-pv-storage
persistentVolumeClaim:
claimName: theodolite-pv-claim
- - name: app-resources
+ - name: benchmark-resources
configMap:
- name: app-resources-configmap
+ name: benchmark-resources-configmap
- name: benchmark
configMap:
name: benchmark-configmap
diff --git a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-standalone.yaml
index 12cbd8ea310423d28e35de8185288b27257c15ec..871210c213b70070e2aae8f4986058763be74b7e 100644
--- a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-standalone.yaml
+++ b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-standalone.yaml
@@ -22,7 +22,7 @@ loadTypes:
- type: NumSensorsLoadGeneratorReplicaPatcher
resource: "uc1-load-generator-deployment.yaml"
properties:
- loadGenMaxRecords: "15000"
+ loadGenMaxRecords: "150000"
kafkaConfig:
bootstrapServer: "theodolite-cp-kafka:9092"
topics:
diff --git a/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-standalone.yaml
index e38f83f5b05d05febb59c2f775a29b2d545acf0e..48269b38a086f074ead80964df3bd4633742743e 100644
--- a/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-standalone.yaml
+++ b/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-standalone.yaml
@@ -23,7 +23,7 @@ loadTypes:
- type: NumSensorsLoadGeneratorReplicaPatcher
resource: "uc2-load-generator-deployment.yaml"
properties:
- loadGenMaxRecords: "15000"
+ loadGenMaxRecords: "150000"
kafkaConfig:
bootstrapServer: "theodolite-cp-kafka:9092"
topics:
diff --git a/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-standalone.yaml
index e00c1672c4a5a02128c2618b525573a4cddd6c72..0c2311388f1dfa87e8a182eb8399020bc83ae4ce 100644
--- a/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-standalone.yaml
+++ b/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-standalone.yaml
@@ -23,7 +23,7 @@ loadTypes:
- type: NumSensorsLoadGeneratorReplicaPatcher
resource: "uc3-load-generator-deployment.yaml"
properties:
- loadGenMaxRecords: "15000"
+ loadGenMaxRecords: "150000"
kafkaConfig:
bootstrapServer: "theodolite-cp-kafka:9092"
topics:
diff --git a/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-standalone.yaml
index 96e72c9b6d726267044464cce6deb32f60442e96..ec7a67db4ea24547bc23d5c57e7b907ba489859c 100644
--- a/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-standalone.yaml
+++ b/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-standalone.yaml
@@ -23,7 +23,7 @@ loadTypes:
- type: "NumNestedGroupsLoadGeneratorReplicaPatcher"
resource: "uc4-load-generator-deployment.yaml"
properties:
- loadGenMaxRecords: "15000"
+ loadGenMaxRecords: "150000"
numSensors: "4.0"
kafkaConfig:
bootstrapServer: "theodolite-cp-kafka:9092"
diff --git a/theodolite/.dockerignore b/theodolite/.dockerignore
index d95caadc42523460fa9d78cf17629c8ee231acc9..680e535674de90720f521c92a5ad518100f906b8 100644
--- a/theodolite/.dockerignore
+++ b/theodolite/.dockerignore
@@ -3,4 +3,3 @@
!build/*-runner.jar
!build/lib/*
!build/quarkus-app/*
-!config/*
\ No newline at end of file
diff --git a/theodolite/config/README.md b/theodolite/config/README.md
deleted file mode 100644
index 23337d77375ebba8f624e7a11f714502fe3d5e67..0000000000000000000000000000000000000000
--- a/theodolite/config/README.md
+++ /dev/null
@@ -1,201 +0,0 @@
-## 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
- properties:
- <Patcher Arguments> ...
- ...
-loadTypes:
- - typeName: String
- patchers:
- - type: String
- resources: String
- properties:
- <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.
- * **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:
- * **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.
- * **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.
- * **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
- properties:
- <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.
- * **properties**: *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"
- * **properties**:
- * container: "workload-generator"
- * variableName: "NUM_SENSORS"
-
-* **NodeSelectorPatcher**: Changes the node selection field in kubernetes resources.
- * **type**: "NodeSelectorPatcher"
- * **resource**: "uc1-load-generator-deployment.yaml"
- * **properties**:
- * variableName: "env"
- * **value**: "prod"
-
-* **ResourceLimitPatcher**: Changes the resource limit for a kubernetes resource.
- * **resource**: "uc1-kstreams-deployment.yaml"
- * **properties**:
- * 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"
- * **properties**:
- * 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/config/aggregation-service.yaml b/theodolite/config/aggregation-service.yaml
deleted file mode 100644
index 85432d04f225c30469f3232153ef6bd72bd02bdf..0000000000000000000000000000000000000000
--- a/theodolite/config/aggregation-service.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
- name: titan-ccp-aggregation
- labels:
- app: titan-ccp-aggregation
-spec:
- #type: NodePort
- selector:
- app: titan-ccp-aggregation
- ports:
- - name: http
- port: 80
- targetPort: 80
- protocol: TCP
- - name: metrics
- port: 5556
diff --git a/theodolite/config/jmx-configmap.yaml b/theodolite/config/jmx-configmap.yaml
deleted file mode 100644
index 78496a86b1242a89b9e844ead3e700fd0b9a9667..0000000000000000000000000000000000000000
--- a/theodolite/config/jmx-configmap.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: aggregation-jmx-configmap
-data:
- jmx-kafka-prometheus.yml: |+
- jmxUrl: service:jmx:rmi:///jndi/rmi://localhost:5555/jmxrmi
- lowercaseOutputName: true
- lowercaseOutputLabelNames: true
- ssl: false
diff --git a/theodolite/config/service-monitor.yaml b/theodolite/config/service-monitor.yaml
deleted file mode 100644
index 4e7e758cacb5086305efa26292ddef2afc958096..0000000000000000000000000000000000000000
--- a/theodolite/config/service-monitor.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-apiVersion: monitoring.coreos.com/v1
-kind: ServiceMonitor
-metadata:
- labels:
- app: titan-ccp-aggregation
- appScope: titan-ccp
- name: titan-ccp-aggregation
-spec:
- selector:
- matchLabels:
- app: titan-ccp-aggregation
- endpoints:
- - port: metrics
- interval: 10s
diff --git a/theodolite/config/uc1-kstreams-deployment.yaml b/theodolite/config/uc1-kstreams-deployment.yaml
deleted file mode 100644
index 171c3446db2719ee91bd8954233015316851fcf9..0000000000000000000000000000000000000000
--- a/theodolite/config/uc1-kstreams-deployment.yaml
+++ /dev/null
@@ -1,55 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: titan-ccp-aggregation
-spec:
- selector:
- matchLabels:
- app: titan-ccp-aggregation
- replicas: 1
- template:
- metadata:
- labels:
- app: titan-ccp-aggregation
- spec:
- terminationGracePeriodSeconds: 0
- containers:
- - name: uc-application
- image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest
- ports:
- - containerPort: 5555
- name: jmx
- env:
- - name: KAFKA_BOOTSTRAP_SERVERS
- value: "theodolite-cp-kafka:9092"
- - name: SCHEMA_REGISTRY_URL
- value: "http://theodolite-cp-schema-registry:8081"
- - name: JAVA_OPTS
- value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=5555"
- - name: COMMIT_INTERVAL_MS # Set as default for the applications
- value: "100"
- resources:
- limits:
- memory: 4Gi
- cpu: 1000m
- - name: prometheus-jmx-exporter
- image: "solsson/kafka-prometheus-jmx-exporter@sha256:6f82e2b0464f50da8104acd7363fb9b995001ddff77d248379f8788e78946143"
- command:
- - java
- - -XX:+UnlockExperimentalVMOptions
- - -XX:+UseCGroupMemoryLimitForHeap
- - -XX:MaxRAMFraction=1
- - -XshowSettings:vm
- - -jar
- - jmx_prometheus_httpserver.jar
- - "5556"
- - /etc/jmx-aggregation/jmx-kafka-prometheus.yml
- ports:
- - containerPort: 5556
- volumeMounts:
- - name: jmx-config
- mountPath: /etc/jmx-aggregation
- volumes:
- - name: jmx-config
- configMap:
- name: aggregation-jmx-configmap
\ No newline at end of file
diff --git a/theodolite/config/uc1-load-generator-deployment.yaml b/theodolite/config/uc1-load-generator-deployment.yaml
deleted file mode 100644
index 374dd60113e133ef0a793149e3786efb38973287..0000000000000000000000000000000000000000
--- a/theodolite/config/uc1-load-generator-deployment.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: titan-ccp-load-generator
-spec:
- selector:
- matchLabels:
- app: titan-ccp-load-generator
- replicas: 1
- template:
- metadata:
- labels:
- app: titan-ccp-load-generator
- spec:
- terminationGracePeriodSeconds: 0
- containers:
- - name: workload-generator
- image: ghcr.io/cau-se/theodolite-uc1-workload-generator:latest
- ports:
- - containerPort: 5701
- name: coordination
- env:
- - name: NUM_SENSORS
- value: "25000"
- - name: NUM_NESTED_GROUPS
- value: "5"
- - name: KUBERNETES_NAMESPACE
- valueFrom:
- fieldRef:
- fieldPath: metadata.namespace
- - name: KUBERNETES_DNS_NAME
- value: "titan-ccp-load-generator.$(KUBERNETES_NAMESPACE).svc.cluster.local"
- - name: KAFKA_BOOTSTRAP_SERVERS
- value: "theodolite-cp-kafka:9092"
- - name: SCHEMA_REGISTRY_URL
- value: "http://theodolite-cp-schema-registry:8081"
diff --git a/theodolite/config/uc1-load-generator-service.yaml b/theodolite/config/uc1-load-generator-service.yaml
deleted file mode 100644
index f8b26b3f6dece427f9c1ad4db94e351b042749b3..0000000000000000000000000000000000000000
--- a/theodolite/config/uc1-load-generator-service.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
- name: titan-ccp-load-generator
- labels:
- app: titan-ccp-load-generator
-spec:
- type: ClusterIP
- clusterIP: None
- selector:
- app: titan-ccp-load-generator
- ports:
- - name: coordination
- port: 5701
- targetPort: 5701
- protocol: TCP
diff --git a/theodolite/config/uc1-service-monitor.yaml b/theodolite/config/uc1-service-monitor.yaml
deleted file mode 100644
index 4e7e758cacb5086305efa26292ddef2afc958096..0000000000000000000000000000000000000000
--- a/theodolite/config/uc1-service-monitor.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-apiVersion: monitoring.coreos.com/v1
-kind: ServiceMonitor
-metadata:
- labels:
- app: titan-ccp-aggregation
- appScope: titan-ccp
- name: titan-ccp-aggregation
-spec:
- selector:
- matchLabels:
- app: titan-ccp-aggregation
- endpoints:
- - port: metrics
- interval: 10s
diff --git a/theodolite/src/main/docker/Dockerfile.jvm b/theodolite/src/main/docker/Dockerfile.jvm
index 4800a03181194772f854a85a9b0ba0eed17365ec..4d51240e0225bb571cc4a625e40c9ec76fd8f10d 100644
--- a/theodolite/src/main/docker/Dockerfile.jvm
+++ b/theodolite/src/main/docker/Dockerfile.jvm
@@ -44,7 +44,6 @@ RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
COPY build/lib/* /deployments/lib/
COPY build/*-runner.jar /deployments/app.jar
-COPY config/ /deployments/config/
EXPOSE 8080
USER 1001
diff --git a/theodolite/src/main/docker/Dockerfile.native b/theodolite/src/main/docker/Dockerfile.native
index d03e77564f783b76d202986ebd7c1e336f013779..95ef4fb51d7dc1ac520fb4c5a9af1b2d0a32fd09 100644
--- a/theodolite/src/main/docker/Dockerfile.native
+++ b/theodolite/src/main/docker/Dockerfile.native
@@ -20,7 +20,6 @@ RUN chown 1001 /deployments \
&& chmod "g+rwX" /deployments \
&& chown 1001:root /deployments
COPY --chown=1001:root build/*-runner /deployments/application
-COPY config/ /deployments/config/
EXPOSE 8080
USER 1001
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt b/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt
index d57a28e8bbcf4dc101e4814ecaa0d52fe28c08a9..05d021b1bcfb77fa8ffeb0522510d49e39ef501c 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt
@@ -1,8 +1,5 @@
package theodolite.benchmark
-import io.fabric8.kubernetes.api.model.KubernetesResource
-import io.fabric8.kubernetes.api.model.Namespaced
-import io.fabric8.kubernetes.client.CustomResource
import io.quarkus.runtime.annotations.RegisterForReflection
import theodolite.util.ConfigurationOverride
import theodolite.util.LoadDimension
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
index 62ab75898d16ff2732ab6aa5c254ec8f87fb7266..63b554e6a023d9b39b16c8a130b7fbf00926acdd 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
@@ -18,7 +18,7 @@ import kotlin.properties.Delegates
* - An [execution] that encapsulates: the strategy, the duration, and the restrictions
* for the execution of the benchmark.
* - [configOverrides] additional configurations.
- * This class is used for parsing(in [theodolite.execution.TheodoliteYamlExecutor]) and
+ * This class is used for parsing(in [theodolite.execution.TheodoliteStandalone]) and
* for the deserializing in the [theodolite.execution.operator.TheodoliteOperator].
* @constructor construct an empty BenchmarkExecution.
*/
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KafkaLagExporterRemover.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KafkaLagExporterRemover.kt
deleted file mode 100644
index e8179b42d40e40e7ed45a8f5c48fe26f235be334..0000000000000000000000000000000000000000
--- a/theodolite/src/main/kotlin/theodolite/benchmark/KafkaLagExporterRemover.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package theodolite.benchmark
-
-import io.fabric8.kubernetes.client.NamespacedKubernetesClient
-import mu.KotlinLogging
-
-private val logger = KotlinLogging.logger {}
-
-/**
- * Used to reset the KafkaLagExporter by deleting the pod.
- * @param client NamespacedKubernetesClient used for the deletion.
- */
-class KafkaLagExporterRemover(private val client: NamespacedKubernetesClient) {
-
- /**
- * Deletes all pods with the selected label.
- * @param [label] of the pod that should be deleted.
- */
- fun remove(label: String) {
- this.client.pods().withLabel(label).delete()
- logger.info { "Pod with label: $label deleted" }
- }
-}
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
index 3151aca295d2d9bed9c9b24750090f4c433739b1..309cd9513752850db2bd1a90eecff6139f9c7c24 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
@@ -13,6 +13,7 @@ import theodolite.util.*
private val logger = KotlinLogging.logger {}
private var DEFAULT_NAMESPACE = "default"
+private var DEFAULT_THEODOLITE_APP_RESOURCES = "./benchmark-resources"
/**
* Represents a benchmark in Kubernetes. An example for this is the BenchmarkType.yaml
@@ -26,28 +27,20 @@ private var DEFAULT_NAMESPACE = "default"
* - [namespace] for the client,
* - [path] under which the resource yamls can be found.
*
- * This class is used for the parsing(in the [theodolite.execution.TheodoliteYamlExecutor]) and
+ * This class is used for the parsing(in the [theodolite.execution.TheodoliteStandalone]) and
* for the deserializing in the [theodolite.execution.operator.TheodoliteOperator].
* @constructor construct an empty Benchmark.
*/
@JsonDeserialize
@RegisterForReflection
-class KubernetesBenchmark: KubernetesResource, Benchmark{
+class KubernetesBenchmark : KubernetesResource, Benchmark {
lateinit var name: String
- // var appResource: List<Pair<String, KubernetesResource>>
- // var loadGenResource: List<Pair<String, KubernetesResource>>
lateinit var resourceTypes: List<TypeName>
lateinit var loadTypes: List<TypeName>
lateinit var kafkaConfig: KafkaConfig
lateinit var appResourceSets: List<ResourceSets>
lateinit var loadGenResourceSets: List<ResourceSets>
var namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
- var path = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
-
- // init {
- // this.appResource = appResourceSets.flatMap { it.loadResourceSet() }
- // this.loadGenResource = loadGenResourceSets.flatMap { it.loadResourceSet() }
- // }
/**
* Loads [KubernetesResource]s.
@@ -75,7 +68,6 @@ class KubernetesBenchmark: KubernetesResource, Benchmark{
afterTeardownDelay: Long
): BenchmarkDeployment {
logger.info { "Using $namespace as namespace." }
- logger.info { "Using $path as resource path." }
val appResources = loadKubernetesResources(this.appResourceSets)
val loadGenResources = loadKubernetesResources(this.loadGenResourceSets)
@@ -97,7 +89,6 @@ class KubernetesBenchmark: KubernetesResource, Benchmark{
}
}
return KubernetesBenchmarkDeployment(
- namespace = namespace,
appResources = appResources.map { it.second },
loadGenResources = loadGenResources.map { it.second },
loadGenerationDelay = loadGenerationDelay,
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
index 6cf239676ddb24752f4754a85fc62657f9eb6603..423ac92c654ff55057796d9642c2cb408bc62fe5 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
@@ -6,6 +6,7 @@ import io.quarkus.runtime.annotations.RegisterForReflection
import mu.KotlinLogging
import org.apache.kafka.clients.admin.NewTopic
import theodolite.k8s.K8sManager
+import theodolite.k8s.ResourceByLabelHandler
import theodolite.k8s.TopicManager
import theodolite.util.KafkaConfig
import java.time.Duration
@@ -22,7 +23,6 @@ private val logger = KotlinLogging.logger {}
*/
@RegisterForReflection
class KubernetesBenchmarkDeployment(
- val namespace: String,
val appResources: List<KubernetesResource>,
val loadGenResources: List<KubernetesResource>,
private val loadGenerationDelay: Long,
@@ -33,7 +33,8 @@ class KubernetesBenchmarkDeployment(
) : BenchmarkDeployment {
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 LAG_EXPORTER_POD_LABEL_NAME = "app.kubernetes.io/name"
+ private val LAG_EXPORTER_POD_LABEL_VALUE = "kafka-lag-exporter"
/**
* Setup a [KubernetesBenchmark] using the [TopicManager] and the [K8sManager]:
@@ -60,7 +61,10 @@ class KubernetesBenchmarkDeployment(
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)
+ ResourceByLabelHandler(client).removePods(
+ labelName = LAG_EXPORTER_POD_LABEL_NAME,
+ labelValue = LAG_EXPORTER_POD_LABEL_VALUE
+ )
logger.info { "Teardown complete. Wait $afterTeardownDelay ms to let everything come down." }
Thread.sleep(Duration.ofSeconds(afterTeardownDelay).toMillis())
}
diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
index ef4d371173c7099eb091f90cddbe26d31e6522be..9037b994d359dbfa67e099d311ca63707dad7c26 100644
--- a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
+++ b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
@@ -12,6 +12,7 @@ import java.util.*
import java.util.regex.Pattern
private val logger = KotlinLogging.logger {}
+private val RECORD_LAG_QUERY = "sum by(group)(kafka_consumergroup_group_lag >= 0)"
/**
* Contains the analysis. Fetches a metric from Prometheus, documents it, and evaluates it.
@@ -32,7 +33,7 @@ class AnalysisExecutor(
* First fetches data from prometheus, then documents them and afterwards evaluate it via a [slo].
* @param load of the experiment.
* @param res of the experiment.
- * @param executionDuration of the experiment.
+ * @param executionIntervals list of start and end points of experiments
* @return true if the experiment succeeded.
*/
fun analyze(load: LoadDimension, res: Resource, executionIntervals: List<Pair<Instant, Instant>>): Boolean {
@@ -45,16 +46,20 @@ class AnalysisExecutor(
val fileURL = "${resultsFolder}exp${executionId}_${load.get()}_${res.get()}_${slo.sloType.toSlug()}"
val prometheusData = executionIntervals
- .map { interval -> fetcher.fetchMetric(
+ .map { interval ->
+ fetcher.fetchMetric(
start = interval.first,
end = interval.second,
- query = "sum by(group)(kafka_consumergroup_group_lag >= 0)") }
+ query = RECORD_LAG_QUERY
+ )
+ }
- prometheusData.forEach{ data ->
+ prometheusData.forEach { data ->
ioHandler.writeToCSVFile(
fileURL = "${fileURL}_${repetitionCounter++}",
data = data.getResultAsList(),
- columns = listOf("group", "timestamp", "value"))
+ columns = listOf("group", "timestamp", "value")
+ )
}
val sloChecker = SloCheckerFactory().create(
@@ -67,6 +72,7 @@ class AnalysisExecutor(
result = sloChecker.evaluate(prometheusData)
} catch (e: Exception) {
+ // TODO(throw exception in order to make it possible to mark an experiment as unsuccessfully)
logger.error { "Evaluation failed for resource '${res.get()}' and load '${load.get()}'. Error: $e" }
}
return result
@@ -75,7 +81,7 @@ class AnalysisExecutor(
private val NONLATIN: Pattern = Pattern.compile("[^\\w-]")
private val WHITESPACE: Pattern = Pattern.compile("[\\s]")
- fun String.toSlug(): String {
+ private fun String.toSlug(): String {
val noWhitespace: String = WHITESPACE.matcher(this).replaceAll("-")
val normalized: String = Normalizer.normalize(noWhitespace, Normalizer.Form.NFD)
val slug: String = NONLATIN.matcher(normalized).replaceAll("")
diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt b/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt
index f7ebee8faf740583dbe6a37381a599e9bde19280..448a2a05f8dbeb1aef153895360bfb40e7275224 100644
--- a/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt
+++ b/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt
@@ -5,7 +5,6 @@ import khttp.post
import mu.KotlinLogging
import theodolite.util.PrometheusResponse
import java.net.ConnectException
-import java.time.Instant
/**
* [SloChecker] that uses an external source for the concrete evaluation.
@@ -37,10 +36,13 @@ class ExternalSloChecker(
*/
override fun evaluate(fetchedData: List<PrometheusResponse>): Boolean {
var counter = 0
- val data = Gson().toJson(mapOf(
- "total_lags" to fetchedData.map { it.data?.result},
- "threshold" to threshold,
- "warmup" to warmup))
+ val data = Gson().toJson(
+ mapOf(
+ "total_lags" to fetchedData.map { it.data?.result },
+ "threshold" to threshold,
+ "warmup" to warmup
+ )
+ )
while (counter < RETRIES) {
val result = post(externalSlopeURL, data = data, timeout = TIMEOUT)
diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloChecker.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloChecker.kt
index 9ee5fe7ef34ce5b6214882ce2c1d19677f1d7130..af70fa5dca3f0556d38791ed96c2af30b9a44a68 100644
--- a/theodolite/src/main/kotlin/theodolite/evaluation/SloChecker.kt
+++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloChecker.kt
@@ -8,13 +8,10 @@ import theodolite.util.PrometheusResponse
*/
interface SloChecker {
/**
- * Evaluates [fetchedData] and returns if the experiment was successful.
- * Returns if the evaluated experiment was successful.
+ * Evaluates [fetchedData] and returns if the experiments were successful.
*
- * @param start of the experiment
- * @param end of the experiment
* @param fetchedData from Prometheus that will be evaluated.
- * @return true if experiment was successful. Otherwise false.
+ * @return true if experiments were successful. Otherwise false.
*/
fun evaluate(fetchedData: List<PrometheusResponse>): Boolean
}
diff --git a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
index 3afc85f0a8cb67011763498a662b447ce2c07f0f..c54d1878d4957a0b8ec6a8fdfb18ec6342d7bfc1 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
@@ -5,7 +5,10 @@ import mu.KotlinLogging
import theodolite.benchmark.Benchmark
import theodolite.benchmark.BenchmarkExecution
import theodolite.evaluation.AnalysisExecutor
-import theodolite.util.*
+import theodolite.util.ConfigurationOverride
+import theodolite.util.LoadDimension
+import theodolite.util.Resource
+import theodolite.util.Results
import java.time.Duration
import java.time.Instant
@@ -22,7 +25,17 @@ class BenchmarkExecutorImpl(
executionId: Int,
loadGenerationDelay: Long,
afterTeardownDelay: Long
-) : BenchmarkExecutor(benchmark, results, executionDuration, configurationOverrides, slo, repetitions, executionId, loadGenerationDelay, afterTeardownDelay) {
+) : BenchmarkExecutor(
+ benchmark,
+ results,
+ executionDuration,
+ configurationOverrides,
+ slo,
+ repetitions,
+ executionId,
+ loadGenerationDelay,
+ afterTeardownDelay
+) {
override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
var result = false
val executionIntervals: MutableList<Pair<Instant, Instant>> = ArrayList()
@@ -30,7 +43,7 @@ class BenchmarkExecutorImpl(
for (i in 1.rangeTo(repetitions)) {
logger.info { "Run repetition $i/$repetitions" }
if (this.run.get()) {
- executionIntervals.add(runSingleExperiment(load,res))
+ executionIntervals.add(runSingleExperiment(load, res))
} else {
break
}
@@ -40,19 +53,27 @@ class BenchmarkExecutorImpl(
* Analyse the experiment, if [run] is true, otherwise the experiment was canceled by the user.
*/
if (this.run.get()) {
- result =AnalysisExecutor(slo = slo, executionId = executionId)
- .analyze(
- load = load,
- res = res,
- executionIntervals = executionIntervals)
+ result = AnalysisExecutor(slo = slo, executionId = executionId)
+ .analyze(
+ load = load,
+ res = res,
+ executionIntervals = executionIntervals
+ )
this.results.setResult(Pair(load, res), result)
}
return result
}
private fun runSingleExperiment(load: LoadDimension, res: Resource): Pair<Instant, Instant> {
- val benchmarkDeployment = benchmark.buildDeployment(load, res, this.configurationOverrides, this.loadGenerationDelay, this.afterTeardownDelay)
+ val benchmarkDeployment = benchmark.buildDeployment(
+ load,
+ res,
+ this.configurationOverrides,
+ this.loadGenerationDelay,
+ this.afterTeardownDelay
+ )
val from = Instant.now()
+ // TODO(restructure try catch in order to throw exceptions if there are significant problems by running a experiment)
try {
benchmarkDeployment.setup()
this.waitAndLog()
@@ -68,6 +89,6 @@ class BenchmarkExecutorImpl(
logger.warn { "Error while tearing down the benchmark deployment." }
logger.debug { "Teardown failed, caused by: $e" }
}
- return Pair(from,to)
+ return Pair(from, to)
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/execution/Main.kt b/theodolite/src/main/kotlin/theodolite/execution/Main.kt
index bf883529967a8b24229fe8256ba0e4edd11b342c..7d5fca859422a194e81468d9766a9e7ba29fb998 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/Main.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/Main.kt
@@ -17,8 +17,8 @@ object Main {
logger.info { "Start Theodolite with mode $mode" }
when (mode) {
- "standalone" -> TheodoliteYamlExecutor().start()
- "yaml-executor" -> TheodoliteYamlExecutor().start() // TODO remove (#209)
+ "standalone" -> TheodoliteStandalone().start()
+ "yaml-executor" -> TheodoliteStandalone().start() // TODO remove (#209)
"operator" -> TheodoliteOperator().start()
else -> {
logger.error { "MODE $mode not found" }
diff --git a/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt b/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt
index 0ff8379a0af4b11154214dde021d7c60609631d1..e795ada3e3bcb2dba19f1e088f426f38a824f4a7 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt
@@ -5,7 +5,6 @@ import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.KubernetesBenchmark
import theodolite.util.LoadDimension
import theodolite.util.Resource
-import java.lang.Exception
private val logger = KotlinLogging.logger {}
@@ -25,22 +24,26 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b
override fun run() {
// Build Configuration to teardown
try {
- logger.info { "Received shutdown signal -> Shutting down" }
- val deployment =
- benchmark.buildDeployment(
- load = LoadDimension(0, emptyList()),
- res = Resource(0, emptyList()),
- configurationOverrides = benchmarkExecution.configOverrides,
- loadGenerationDelay = 0L,
- afterTeardownDelay = 5L
- )
+ logger.info { "Received shutdown signal -> Shutting down" }
+ val deployment =
+ benchmark.buildDeployment(
+ load = LoadDimension(0, emptyList()),
+ res = Resource(0, emptyList()),
+ configurationOverrides = benchmarkExecution.configOverrides,
+ loadGenerationDelay = 0L,
+ afterTeardownDelay = 5L
+ )
deployment.teardown()
} catch (e: Exception) {
- logger.warn { "Could not delete all specified resources from Kubernetes. " +
- "This could be the case, if not all resources are deployed and running." }
+ // TODO(throw exception in order to make it possible to mark an experiment as unsuccessfully)
+ logger.warn {
+ "Could not delete all specified resources from Kubernetes. " +
+ "This could be the case, if not all resources are deployed and running."
+ }
}
- logger.info { "Teardown everything deployed" }
- logger.info { "Teardown completed" }
+ logger.info {
+ "Finished teardown of all benchmark resources."
+ }
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
index c73aaae08489c25a40163d4edb1607247fae010a..f5054dc2d8c3525562118b559ab8987215dc4ea1 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
@@ -70,14 +70,18 @@ class TheodoliteExecutor(
if (config.load.loadValues != config.load.loadValues.sorted()) {
config.load.loadValues = config.load.loadValues.sorted()
- logger.info { "Load values are not sorted correctly, Theodolite sorts them in ascending order." +
- "New order is: ${config.load.loadValues}" }
+ logger.info {
+ "Load values are not sorted correctly, Theodolite sorts them in ascending order." +
+ "New order is: ${config.load.loadValues}"
+ }
}
if (config.resources.resourceValues != config.resources.resourceValues.sorted()) {
config.resources.resourceValues = config.resources.resourceValues.sorted()
- logger.info { "Load values are not sorted correctly, Theodolite sorts them in ascending order." +
- "New order is: ${config.resources.resourceValues}" }
+ logger.info {
+ "Load values are not sorted correctly, Theodolite sorts them in ascending order." +
+ "New order is: ${config.resources.resourceValues}"
+ }
}
return Config(
@@ -103,10 +107,6 @@ class TheodoliteExecutor(
return this.config
}
- fun getBenchmark(): KubernetesBenchmark {
- return this.kubernetesBenchmark
- }
-
/**
* Run all experiments which are specified in the corresponding
* execution and benchmark objects.
@@ -114,9 +114,12 @@ class TheodoliteExecutor(
fun run() {
val ioHandler = IOHandler()
val resultsFolder = ioHandler.getResultFolderURL()
- this.config.executionId = getAndIncrementExecutionID(resultsFolder+"expID.txt")
+ this.config.executionId = getAndIncrementExecutionID(resultsFolder + "expID.txt")
ioHandler.writeToJSONFile(this.config, "$resultsFolder${this.config.executionId}-execution-configuration")
- ioHandler.writeToJSONFile(kubernetesBenchmark, "$resultsFolder${this.config.executionId}-benchmark-configuration")
+ ioHandler.writeToJSONFile(
+ kubernetesBenchmark,
+ "$resultsFolder${this.config.executionId}-benchmark-configuration"
+ )
val config = buildConfig()
// execute benchmarks for each load
@@ -125,17 +128,20 @@ class TheodoliteExecutor(
config.compositeStrategy.findSuitableResource(load, config.resources)
}
}
- ioHandler.writeToJSONFile(config.compositeStrategy.benchmarkExecutor.results, "$resultsFolder${this.config.executionId}-result")
+ ioHandler.writeToJSONFile(
+ config.compositeStrategy.benchmarkExecutor.results,
+ "$resultsFolder${this.config.executionId}-result"
+ )
}
- private fun getAndIncrementExecutionID(fileURL: String): Int {
- val ioHandler = IOHandler()
- var executionID = 0
- if (File(fileURL).exists()) {
- executionID = ioHandler.readFileAsString(fileURL).toInt() + 1
- }
- ioHandler.writeStringToTextFile(fileURL, (executionID).toString())
- return executionID
+ private fun getAndIncrementExecutionID(fileURL: String): Int {
+ val ioHandler = IOHandler()
+ var executionID = 0
+ if (File(fileURL).exists()) {
+ executionID = ioHandler.readFileAsString(fileURL).toInt() + 1
+ }
+ ioHandler.writeStringToTextFile(fileURL, (executionID).toString())
+ return executionID
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteYamlExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteStandalone.kt
similarity index 93%
rename from theodolite/src/main/kotlin/theodolite/execution/TheodoliteYamlExecutor.kt
rename to theodolite/src/main/kotlin/theodolite/execution/TheodoliteStandalone.kt
index 0c62925963db4d45c743eb32c3d80b04da1ffaa1..abb6e7f6ed454f748e0fe50d6a24214b06649d47 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteYamlExecutor.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteStandalone.kt
@@ -25,14 +25,14 @@ private val logger = KotlinLogging.logger {}
*
* @constructor Create empty Theodolite yaml executor
*/
-class TheodoliteYamlExecutor {
+class TheodoliteStandalone {
private val parser = YamlParserFromFile()
fun start() {
logger.info { "Theodolite started" }
- val executionPath = System.getenv("THEODOLITE_EXECUTION") ?: "./config/example-execution-yaml-resource.yaml"
- val benchmarkPath = System.getenv("THEODOLITE_BENCHMARK") ?: "./config/example-benchmark-yaml-resource.yaml"
+ val executionPath = System.getenv("THEODOLITE_EXECUTION") ?: "execution/execution.yaml"
+ val benchmarkPath = System.getenv("THEODOLITE_BENCHMARK") ?: "benchmark/benchmark.yaml"
logger.info { "Using $executionPath for BenchmarkExecution" }
logger.info { "Using $benchmarkPath for BenchmarkType" }
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt
index a7a40cd569f8034f3b8e062dad3031d5643a12e3..9d7436526f18081c7130870956d8a5eea5fc8997 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt
@@ -4,47 +4,50 @@ import io.fabric8.kubernetes.api.model.HasMetadata
import io.fabric8.kubernetes.api.model.KubernetesResourceList
import io.fabric8.kubernetes.api.model.Namespaced
import io.fabric8.kubernetes.client.CustomResource
-import io.fabric8.kubernetes.client.KubernetesClient
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.MixedOperation
import io.fabric8.kubernetes.client.dsl.Resource
import java.lang.Thread.sleep
-abstract class AbstractStateHandler<T,L,D>(
- private val client: KubernetesClient,
+abstract class AbstractStateHandler<T, L, D>(
+ private val client: NamespacedKubernetesClient,
private val crd: Class<T>,
private val crdList: Class<L>
- ): StateHandler<T> where T : CustomResource<*, *>?, T: HasMetadata, T: Namespaced, L: KubernetesResourceList<T> {
+) : StateHandler<T> where T : CustomResource<*, *>?, T : HasMetadata, T : Namespaced, L : KubernetesResourceList<T> {
- private val crdClient: MixedOperation<T, L,Resource<T>> =
+ private val crdClient: MixedOperation<T, L, Resource<T>> =
this.client.customResources(this.crd, this.crdList)
@Synchronized
override fun setState(resourceName: String, f: (T) -> T?) {
this.crdClient
- .inNamespace(this.client.namespace)
.list().items
- .filter { item -> item.metadata.name == resourceName }
+ .filter { it.metadata.name == resourceName }
.map { customResource -> f(customResource) }
.forEach { this.crdClient.updateStatus(it) }
- }
+ }
@Synchronized
override fun getState(resourceName: String, f: (T) -> String?): String? {
return this.crdClient
- .inNamespace(this.client.namespace)
.list().items
- .filter { item -> item.metadata.name == resourceName }
+ .filter { it.metadata.name == resourceName }
.map { customResource -> f(customResource) }
.firstOrNull()
}
@Synchronized
- override fun blockUntilStateIsSet(resourceName: String, desiredStatusString: String, f: (T) -> String?, maxTries: Int): Boolean {
+ override fun blockUntilStateIsSet(
+ resourceName: String,
+ desiredStatusString: String,
+ f: (T) -> String?,
+ maxTries: Int
+ ): Boolean {
for (i in 0.rangeTo(maxTries)) {
val currentStatus = getState(resourceName, f)
- if(currentStatus == desiredStatusString) {
- return true
- }
+ if (currentStatus == desiredStatusString) {
+ return true
+ }
sleep(50)
}
return false
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt
index 8fc951d09598187bcaf4cb7e4a39d322be722792..c3a2b7b25ed71e797c45d8b497bad6cad15e21e8 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt
@@ -4,9 +4,9 @@ import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.MixedOperation
import io.fabric8.kubernetes.client.dsl.Resource
import mu.KotlinLogging
-import org.json.JSONObject
import theodolite.execution.Shutdown
import theodolite.k8s.K8sContextFactory
+import theodolite.k8s.ResourceByLabelHandler
import theodolite.model.crd.*
private val logger = KotlinLogging.logger {}
@@ -16,7 +16,7 @@ class ClusterSetup(
private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>,
private val client: NamespacedKubernetesClient
- ) {
+) {
private val serviceMonitorContext = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
@@ -24,18 +24,24 @@ class ClusterSetup(
plural = "servicemonitors"
)
- fun clearClusterState(){
+ fun clearClusterState() {
stopRunningExecution()
clearByLabel()
}
+ /**
+ * This function searches for executions in the cluster that have the status running and tries to stop the execution.
+ * For this the corresponding benchmark is searched and terminated.
+ *
+ * Throws [IllegalStateException] if no suitable benchmark can be found.
+ *
+ */
private fun stopRunningExecution() {
executionCRDClient
- .inNamespace(client.namespace)
.list()
.items
.asSequence()
- .filter { it.status.executionState == States.RUNNING.value }
+ .filter { it.status.executionState == States.RUNNING.value }
.forEach { execution ->
val benchmark = benchmarkCRDClient
.inNamespace(client.namespace)
@@ -50,27 +56,35 @@ class ClusterSetup(
} else {
logger.error {
"Execution with state ${States.RUNNING.value} was found, but no corresponding benchmark. " +
- "Could not initialize cluster." }
+ "Could not initialize cluster."
+ }
+ throw IllegalStateException("Cluster state is invalid, required Benchmark for running execution not found.")
}
-
-
}
- }
-
- private fun clearByLabel() {
- this.client.services().withLabel("app.kubernetes.io/created-by=theodolite").delete()
- this.client.apps().deployments().withLabel("app.kubernetes.io/created-by=theodolite").delete()
- this.client.apps().statefulSets().withLabel("app.kubernetes.io/created-by=theodolite").delete()
- this.client.configMaps().withLabel("app.kubernetes.io/created-by=theodolite").delete()
+ }
- val serviceMonitors = JSONObject(
- this.client.customResource(serviceMonitorContext)
- .list(client.namespace, mapOf(Pair("app.kubernetes.io/created-by", "theodolite")))
+ private fun clearByLabel() {
+ val resourceRemover = ResourceByLabelHandler(client = client)
+ resourceRemover.removeServices(
+ labelName = "app.kubernetes.io/created-by",
+ labelValue = "theodolite"
+ )
+ resourceRemover.removeDeployments(
+ labelName = "app.kubernetes.io/created-by",
+ labelValue = "theodolite"
+ )
+ resourceRemover.removeStatefulSets(
+ labelName = "app.kubernetes.io/created-by",
+ labelValue = "theodolite"
+ )
+ resourceRemover.removeConfigMaps(
+ labelName = "app.kubernetes.io/created-by",
+ labelValue = "theodolite"
+ )
+ resourceRemover.removeCR(
+ labelName = "app.kubernetes.io/created-by",
+ labelValue = "theodolite",
+ context = serviceMonitorContext
)
- .getJSONArray("items")
-
- (0 until serviceMonitors.length())
- .map { serviceMonitors.getJSONObject(it).getJSONObject("metadata").getString("name") }
- .forEach { this.client.customResource(serviceMonitorContext).delete(client.namespace, it) }
}
}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt
index 653366010725a8db816c92aece7bb572b659426b..62c1ddd4eecb41aecde7000eb048455c95cab949 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt
@@ -36,10 +36,10 @@ class ExecutionHandler(
States.NO_STATE -> this.stateHandler.setExecutionState(execution.spec.name, States.PENDING)
States.RUNNING -> {
this.stateHandler.setExecutionState(execution.spec.name, States.RESTART)
- if(this.controller.isExecutionRunning(execution.spec.name)){
- this.controller.stop(restart=true)
- }
+ if (this.controller.isExecutionRunning(execution.spec.name)) {
+ this.controller.stop(restart = true)
}
+ }
}
}
@@ -55,20 +55,21 @@ class ExecutionHandler(
override fun onUpdate(oldExecution: ExecutionCRD, newExecution: ExecutionCRD) {
newExecution.spec.name = newExecution.metadata.name
oldExecution.spec.name = oldExecution.metadata.name
- if(gson.toJson(oldExecution.spec) != gson.toJson(newExecution.spec)) {
+ if (gson.toJson(oldExecution.spec) != gson.toJson(newExecution.spec)) {
logger.info { "Receive update event for execution ${oldExecution.metadata.name}" }
- when(this.stateHandler.getExecutionState(newExecution.metadata.name)) {
+ when (this.stateHandler.getExecutionState(newExecution.metadata.name)) {
States.RUNNING -> {
- this.stateHandler.setExecutionState(newExecution.spec.name, States.RESTART)
- if (this.controller.isExecutionRunning(newExecution.spec.name)){
- this.controller.stop(restart=true)
- }
- }
- States.RESTART -> {} // should this set to pending?
- else -> this.stateHandler.setExecutionState(newExecution.spec.name, States.PENDING)
+ this.stateHandler.setExecutionState(newExecution.spec.name, States.RESTART)
+ if (this.controller.isExecutionRunning(newExecution.spec.name)) {
+ this.controller.stop(restart = true)
+ }
}
+ States.RESTART -> {
+ } // should this set to pending?
+ else -> this.stateHandler.setExecutionState(newExecution.spec.name, States.PENDING)
}
}
+ }
/**
* Delete an execution from the queue of the TheodoliteController.
@@ -78,8 +79,9 @@ class ExecutionHandler(
@Synchronized
override fun onDelete(execution: ExecutionCRD, b: Boolean) {
logger.info { "Delete execution ${execution.metadata.name}" }
- if(execution.status.executionState == States.RUNNING.value
- && this.controller.isExecutionRunning(execution.spec.name)) {
+ if (execution.status.executionState == States.RUNNING.value
+ && this.controller.isExecutionRunning(execution.spec.name)
+ ) {
this.controller.stop()
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt
index df5e77695d1beb562408f1b5830f6f4353543c75..bcc86c8f2a9b233fa9a1972a866936e14688ecf8 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt
@@ -1,6 +1,6 @@
package theodolite.execution.operator
-import io.fabric8.kubernetes.client.KubernetesClient
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import theodolite.model.crd.BenchmarkExecutionList
import theodolite.model.crd.ExecutionCRD
import theodolite.model.crd.ExecutionStatus
@@ -10,8 +10,8 @@ import java.time.Duration
import java.time.Instant
import java.util.concurrent.atomic.AtomicBoolean
-class ExecutionStateHandler(val client: KubernetesClient):
- AbstractStateHandler<ExecutionCRD, BenchmarkExecutionList, ExecutionStatus >(
+class ExecutionStateHandler(val client: NamespacedKubernetesClient) :
+ AbstractStateHandler<ExecutionCRD, BenchmarkExecutionList, ExecutionStatus>(
client = client,
crd = ExecutionCRD::class.java,
crdList = BenchmarkExecutionList::class.java
@@ -24,13 +24,13 @@ class ExecutionStateHandler(val client: KubernetesClient):
private fun getDurationLambda() = { cr: ExecutionCRD -> cr.status.executionDuration }
fun setExecutionState(resourceName: String, status: States): Boolean {
- setState(resourceName) {cr -> cr.status.executionState = status.value; cr}
+ setState(resourceName) { cr -> cr.status.executionState = status.value; cr }
return blockUntilStateIsSet(resourceName, status.value, getExecutionLambda())
}
- fun getExecutionState(resourceName: String) : States {
+ fun getExecutionState(resourceName: String): States {
val status = this.getState(resourceName, getExecutionLambda())
- return if(status.isNullOrBlank()){
+ return if (status.isNullOrBlank()) {
States.NO_STATE
} else {
States.values().first { it.value == status }
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/LeaderElector.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/LeaderElector.kt
index 9d093e4851e5c43d29a3fea3057ccf01be612e63..1ce94c2fdd1ce13d50a21e01b9d4692c87d0da6f 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/LeaderElector.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/LeaderElector.kt
@@ -13,14 +13,15 @@ import kotlin.reflect.KFunction0
private val logger = KotlinLogging.logger {}
class LeaderElector(
- val client: NamespacedKubernetesClient,
+ val client: NamespacedKubernetesClient,
val name: String
- ) {
+) {
+ // TODO(what is the name of the lock? .withName() or LeaseLock(..,name..) ?)
fun getLeadership(leader: KFunction0<Unit>) {
val lockIdentity: String = UUID.randomUUID().toString()
- DefaultKubernetesClient().use { kc ->
- kc.leaderElector()
+ DefaultKubernetesClient().use { kc ->
+ kc.leaderElector()
.withConfig(
LeaderElectionConfigBuilder()
.withName("Theodolite")
@@ -29,10 +30,10 @@ class LeaderElector(
.withRenewDeadline(Duration.ofSeconds(10L))
.withRetryPeriod(Duration.ofSeconds(2L))
.withLeaderCallbacks(LeaderCallbacks(
- { Thread{leader()}.start() },
+ { Thread { leader() }.start() },
{ logger.info { "STOPPED LEADERSHIP" } }
) { newLeader: String? ->
- logger.info { "New leader elected $newLeader" }
+ logger.info { "New leader elected $newLeader" }
})
.build()
)
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/StateHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/StateHandler.kt
index cefcf2ec97986375205205fd95ddcd2ff7eacf5a..e2cfaa354443cdc940abf92ef2c7474d028daecf 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/StateHandler.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/StateHandler.kt
@@ -9,6 +9,7 @@ interface StateHandler<T> {
resourceName: String,
desiredStatusString: String,
f: (T) -> String?,
- maxTries: Int = MAX_TRIES): Boolean
+ maxTries: Int = MAX_TRIES
+ ): Boolean
}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
index 3a556b44fd8f9e7ed14298a0094e44fbf11dde3e..d1c0df7887526494a8c27521bcb81770d85d0c1f 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
@@ -7,11 +7,15 @@ import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.KubernetesBenchmark
import theodolite.execution.TheodoliteExecutor
import theodolite.model.crd.*
-import theodolite.util.ConfigurationOverride
-import theodolite.util.PatcherDefinition
+import theodolite.patcher.ConfigOverrideModifier
+import theodolite.util.ExecutionStateComparator
import java.lang.Thread.sleep
private val logger = KotlinLogging.logger {}
+const val DEPLOYED_FOR_EXECUTION_LABEL_NAME = "deployed-for-execution"
+const val DEPLOYED_FOR_BENCHMARK_LABEL_NAME = "deployed-for-benchmark"
+const val CREATED_BY_LABEL_NAME = "app.kubernetes.io/created-by"
+const val CREATED_BY_LABEL_VALUE = "theodolite"
/**
* The controller implementation for Theodolite.
@@ -22,7 +26,6 @@ private val logger = KotlinLogging.logger {}
*/
class TheodoliteController(
- val path: String,
private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, Resource<ExecutionCRD>>,
private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>,
private val executionStateHandler: ExecutionStateHandler
@@ -62,21 +65,23 @@ class TheodoliteController(
* @see BenchmarkExecution
*/
private fun runExecution(execution: BenchmarkExecution, benchmark: KubernetesBenchmark) {
- setAdditionalLabels(execution.name,
- "deployed-for-execution",
- benchmark.appResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } }
- + benchmark.loadGenResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } },
- execution)
- setAdditionalLabels(benchmark.name,
- "deployed-for-benchmark",
- benchmark.appResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } }
- + benchmark.loadGenResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } },
- execution)
- setAdditionalLabels("theodolite",
- "app.kubernetes.io/created-by",
- benchmark.appResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } }
- + benchmark.loadGenResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } },
- execution)
+ val modifier = ConfigOverrideModifier(
+ execution = execution,
+ resources = benchmark.appResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } }
+ + benchmark.loadGenResourceSets.flatMap { it -> it.loadResourceSet().map { it.first } }
+ )
+ modifier.setAdditionalLabels(
+ labelValue = execution.name,
+ labelName = DEPLOYED_FOR_EXECUTION_LABEL_NAME
+ )
+ modifier.setAdditionalLabels(
+ labelValue = benchmark.name,
+ labelName = DEPLOYED_FOR_BENCHMARK_LABEL_NAME
+ )
+ modifier.setAdditionalLabels(
+ labelValue = CREATED_BY_LABEL_VALUE,
+ labelName = CREATED_BY_LABEL_NAME
+ )
executionStateHandler.setExecutionState(execution.name, States.RUNNING)
executionStateHandler.startDurationStateTimer(execution.name)
@@ -104,9 +109,6 @@ class TheodoliteController(
if (!::executor.isInitialized) return
if (restart) {
executionStateHandler.setExecutionState(this.executor.getExecution().name, States.RESTART)
- } else {
- executionStateHandler.setExecutionState(this.executor.getExecution().name, States.INTERRUPTED)
- logger.warn { "Execution ${executor.getExecution().name} unexpected interrupted" }
}
this.executor.executor.run.set(false)
}
@@ -118,9 +120,10 @@ class TheodoliteController(
return this.benchmarkCRDClient
.list()
.items
- .map { it.spec.name = it.metadata.name; it }
- .map { it.spec.path = path; it } // TODO check if we can remove the path field from the KubernetesBenchmark
- .map { it.spec }
+ .map {
+ it.spec.name = it.metadata.name
+ it.spec
+ }
}
/**
@@ -135,6 +138,7 @@ class TheodoliteController(
* @return the next execution or null
*/
private fun getNextExecution(): BenchmarkExecution? {
+ val comparator = ExecutionStateComparator(States.RESTART)
val availableBenchmarkNames = getBenchmarks()
.map { it.name }
@@ -148,46 +152,13 @@ class TheodoliteController(
it.status.executionState == States.RESTART.value
}
.filter { availableBenchmarkNames.contains(it.spec.benchmark) }
- .sortedWith(stateComparator().thenBy { it.metadata.creationTimestamp })
+ .sortedWith(comparator.thenBy { it.metadata.creationTimestamp })
.map { it.spec }
.firstOrNull()
}
- /**
- * Simple comparator which can be used to order a list of [ExecutionCRD] such that executions with
- * status [States.RESTART] are before all other executions.
- */
- private fun stateComparator() = Comparator<ExecutionCRD> { a, b ->
- when {
- (a == null && b == null) -> 0
- (a.status.executionState == States.RESTART.value) -> -1
- else -> 1
- }
- }
-
fun isExecutionRunning(executionName: String): Boolean {
if (!::executor.isInitialized) return false
return this.executor.getExecution().name == executionName
}
-
- private fun setAdditionalLabels(
- labelValue: String,
- labelName: String,
- resources: List<String>,
- execution: BenchmarkExecution
- ) {
- val additionalConfigOverrides = mutableListOf<ConfigurationOverride>()
- resources.forEach {
- run {
- val configurationOverride = ConfigurationOverride()
- configurationOverride.patcher = PatcherDefinition()
- configurationOverride.patcher.type = "LabelPatcher"
- configurationOverride.patcher.properties = mutableMapOf("variableName" to labelName)
- configurationOverride.patcher.resource = it
- configurationOverride.value = labelValue
- additionalConfigOverrides.add(configurationOverride)
- }
- }
- execution.configOverrides.addAll(additionalConfigOverrides)
- }
}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt
index b489ff74261aafceafd021ca3c32c8dbd192d814..1cb1d8e4bc5ffee89e47aa23546b6e6100d33e9b 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt
@@ -28,7 +28,6 @@ private val logger = KotlinLogging.logger {}
*/
class TheodoliteOperator {
private val namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
- private val appResource = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
private lateinit var controller: TheodoliteController
@@ -38,7 +37,7 @@ class TheodoliteOperator {
fun start() {
LeaderElector(
client = client,
- name = "theodolite-operator"
+ name = "theodolite-operator" // TODO(make leaslock name configurable via env var)
)
.getLeadership(::startOperator)
}
@@ -76,7 +75,10 @@ class TheodoliteOperator {
}
}
- fun getExecutionEventHandler(controller: TheodoliteController, client: NamespacedKubernetesClient): SharedInformerFactory {
+ fun getExecutionEventHandler(
+ controller: TheodoliteController,
+ client: NamespacedKubernetesClient
+ ): SharedInformerFactory {
val factory = client.informers()
.inNamespace(client.namespace)
@@ -105,7 +107,6 @@ class TheodoliteOperator {
): TheodoliteController {
if (!::controller.isInitialized) {
this.controller = TheodoliteController(
- path = this.appResource,
benchmarkCRDClient = getBenchmarkClient(client),
executionCRDClient = getExecutionClient(client),
executionStateHandler = executionStateHandler
diff --git a/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt b/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt
index 31a95be04e3290e0797dca5c588394ea36279b0c..ab355677ec53216072fb58a170610aa5f12dba28 100644
--- a/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt
+++ b/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt
@@ -7,7 +7,10 @@ import mu.KotlinLogging
private val logger = KotlinLogging.logger {}
-class CustomResourceWrapper(val crAsMap: Map<String, String>, private val context: CustomResourceDefinitionContext) : KubernetesResource {
+class CustomResourceWrapper(
+ private val crAsMap: Map<String, String>,
+ private val context: CustomResourceDefinitionContext
+) : KubernetesResource {
/**
* Deploy a service monitor
*
@@ -41,9 +44,4 @@ class CustomResourceWrapper(val crAsMap: Map<String, String>, private val contex
val metadataAsMap = this.crAsMap["metadata"]!! as Map<String, String>
return metadataAsMap["name"]!!
}
-
- fun getLabels(): Map<String, String>{
- val metadataAsMap = this.crAsMap["metadata"]!! as Map<String, String>
- return metadataAsMap["labels"]!! as Map<String, String>
- }
}
diff --git a/theodolite/src/main/kotlin/theodolite/k8s/K8sManager.kt b/theodolite/src/main/kotlin/theodolite/k8s/K8sManager.kt
index 77350868500ffa974ab2b9fadfb8cfd915c8aaf2..abeb1c514d100fc3a12bd8f210e89d65eff9b2cf 100644
--- a/theodolite/src/main/kotlin/theodolite/k8s/K8sManager.kt
+++ b/theodolite/src/main/kotlin/theodolite/k8s/K8sManager.kt
@@ -43,9 +43,12 @@ class K8sManager(private val client: NamespacedKubernetesClient) {
fun remove(resource: KubernetesResource) {
when (resource) {
is Deployment -> {
- val label = resource.spec.selector.matchLabels["app"]!!
this.client.apps().deployments().delete(resource)
- blockUntilPodsDeleted(label)
+ ResourceByLabelHandler(client = client)
+ .blockUntilPodsDeleted(
+ labelName = "app",
+ labelValue = resource.spec.selector.matchLabels["app"]!!
+ )
logger.info { "Deployment '${resource.metadata.name}' deleted." }
}
is Service ->
@@ -53,21 +56,16 @@ class K8sManager(private val client: NamespacedKubernetesClient) {
is ConfigMap ->
this.client.configMaps().delete(resource)
is StatefulSet -> {
- val label = resource.spec.selector.matchLabels["app"]!!
this.client.apps().statefulSets().delete(resource)
- blockUntilPodsDeleted(label)
+ ResourceByLabelHandler(client = client)
+ .blockUntilPodsDeleted(
+ labelName = "app",
+ labelValue = resource.spec.selector.matchLabels["app"]!!
+ )
logger.info { "StatefulSet '$resource.metadata.name' deleted." }
}
is CustomResourceWrapper -> resource.delete(client)
else -> throw IllegalArgumentException("Unknown Kubernetes resource.")
}
}
-
- private fun blockUntilPodsDeleted(podLabel: String) {
- while (!this.client.pods().withLabel(podLabel).list().items.isNullOrEmpty()) {
- logger.info { "Wait for pods with label '$podLabel' to be deleted." }
- Thread.sleep(1000)
- }
- }
-
}
diff --git a/theodolite/src/main/kotlin/theodolite/k8s/ResourceByLabelHandler.kt b/theodolite/src/main/kotlin/theodolite/k8s/ResourceByLabelHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9f3754c54f4b1eeb018b55787974179647f726b6
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/k8s/ResourceByLabelHandler.kt
@@ -0,0 +1,115 @@
+package theodolite.k8s
+
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
+import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
+import mu.KotlinLogging
+import org.json.JSONObject
+
+private val logger = KotlinLogging.logger {}
+
+/**
+ * The ResourceByLabelHandler provides basic functions to manage Kubernetes resources through their labels.
+ * @param client NamespacedKubernetesClient used for the deletion.
+ */
+class ResourceByLabelHandler(private val client: NamespacedKubernetesClient) {
+
+ /**
+ * Deletes all pods with the selected label.
+ * @param [labelName] the label name
+ * @param [labelValue] the value of this label
+ */
+ fun removePods(labelName: String, labelValue: String) {
+ this.client
+ .pods()
+ .withLabel("$labelName=$labelValue").delete()
+ logger.info { "Pod with label: $labelName=$labelValue deleted" }
+ }
+
+ /**
+ * Deletes all services with the selected label.
+ * @param [labelName] the label name
+ * @param [labelValue] the value of this label
+ */
+ fun removeServices(labelName: String, labelValue: String) {
+ this.client
+ .services()
+ .withLabel("$labelName=$labelValue")
+ .delete()
+ }
+
+ /**
+ * Deletes all deployments with the selected label.
+ * @param [labelName] the label name
+ * @param [labelValue] the value of this label
+ */
+ fun removeDeployments(labelName: String, labelValue: String) {
+ this.client
+ .apps()
+ .deployments()
+ .withLabel("$labelName=$labelValue")
+ .delete()
+
+ }
+
+ /**
+ * Deletes all stateful sets with the selected label.
+ * @param [labelName] the label name
+ * @param [labelValue] the value of this label
+ */
+ fun removeStatefulSets(labelName: String, labelValue: String) {
+ this.client
+ .apps()
+ .statefulSets()
+ .withLabel("$labelName=$labelValue")
+ .delete()
+ }
+
+ /**
+ * Deletes all configmaps with the selected label.
+ * @param [labelName] the label name
+ * @param [labelValue] the value of this label
+ */
+ fun removeConfigMaps(labelName: String, labelValue: String) {
+ this.client
+ .configMaps()
+ .withLabel("$labelName=$labelValue")
+ .delete()
+ }
+
+ /**
+ * Deletes all custom resources sets with the selected label.
+ * @param [labelName] the label name
+ * @param [labelValue] the value of this label
+ */
+ fun removeCR(labelName: String, labelValue: String, context: CustomResourceDefinitionContext) {
+ val customResources = JSONObject(
+ this.client.customResource(context)
+ .list(client.namespace, mapOf(Pair(labelName, labelValue)))
+ )
+ .getJSONArray("items")
+
+ (0 until customResources.length())
+ .map { customResources.getJSONObject(it).getJSONObject("metadata").getString("name") }
+ .forEach { this.client.customResource(context).delete(client.namespace, it) }
+ }
+
+ /**
+ * Block until all pods with are deleted
+ *
+ * @param [labelName] the label name
+ * @param [labelValue] the value of this label
+ * */
+ fun blockUntilPodsDeleted(labelName: String, labelValue: String) {
+ while (
+ !this.client
+ .pods()
+ .withLabel("$labelName=$labelValue")
+ .list()
+ .items
+ .isNullOrEmpty()
+ ) {
+ logger.info { "Wait for pods with label $labelName=$labelValue to be deleted." }
+ Thread.sleep(1000)
+ }
+ }
+}
diff --git a/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt b/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt
index 3bbae82d77dc5b01a5827c7ee713bf2566be1bab..8e83883fc881db0f7e2b1b75b2fb7c7322a11a00 100644
--- a/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt
+++ b/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt
@@ -4,7 +4,6 @@ import mu.KotlinLogging
import org.apache.kafka.clients.admin.AdminClient
import org.apache.kafka.clients.admin.CreateTopicsResult
import org.apache.kafka.clients.admin.NewTopic
-import org.apache.kafka.common.errors.TopicExistsException
import java.lang.Thread.sleep
private val logger = KotlinLogging.logger {}
@@ -35,7 +34,7 @@ class TopicManager(private val kafkaConfig: Map<String, Any>) {
logger.debug { e } // TODO remove due to attached exception to warn log?
logger.info { "Remove existing topics." }
delete(newTopics.map { topic -> topic.name() }, kafkaAdmin)
- logger.info { "Will retry the topic creation in ${RETRY_TIME/1000} seconds." }
+ logger.info { "Will retry the topic creation in ${RETRY_TIME / 1000} seconds." }
sleep(RETRY_TIME)
retryCreation = true
}
@@ -104,7 +103,7 @@ class TopicManager(private val kafkaConfig: Map<String, Any>) {
if (toDelete.isNullOrEmpty()) {
deleted = true
} else {
- logger.info { "Deletion of Kafka topics failed, will retry in ${RETRY_TIME/1000} seconds." }
+ logger.info { "Deletion of Kafka topics failed, will retry in ${RETRY_TIME / 1000} seconds." }
sleep(RETRY_TIME)
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/model/crd/ExecutionStatus.kt b/theodolite/src/main/kotlin/theodolite/model/crd/ExecutionStatus.kt
index 51b76fcee8fb35c83dca407691833dbb235b29c5..252738959762aa5d0732babc5589c698d7bd4e9f 100644
--- a/theodolite/src/main/kotlin/theodolite/model/crd/ExecutionStatus.kt
+++ b/theodolite/src/main/kotlin/theodolite/model/crd/ExecutionStatus.kt
@@ -5,7 +5,7 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
import io.fabric8.kubernetes.api.model.Namespaced
@JsonDeserialize
-class ExecutionStatus(): KubernetesResource, Namespaced {
+class ExecutionStatus : KubernetesResource, Namespaced {
var executionState: String = ""
var executionDuration: String = "-"
}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ConfigOverrideModifier.kt b/theodolite/src/main/kotlin/theodolite/patcher/ConfigOverrideModifier.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8f77b1b95f3bf5cc9422cda55cb261048cebaeb6
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ConfigOverrideModifier.kt
@@ -0,0 +1,39 @@
+package theodolite.patcher
+
+import theodolite.benchmark.BenchmarkExecution
+import theodolite.util.ConfigurationOverride
+import theodolite.util.PatcherDefinition
+
+/**
+ * The ConfigOverrideModifier makes it possible to update the configuration overrides of an execution.
+ *
+ * @property execution execution for which the config overrides should be updated
+ * @property resources list of all resources that should be updated.
+ */
+class ConfigOverrideModifier(val execution: BenchmarkExecution, val resources: List<String>) {
+
+ /**
+ * Adds a [LabelPatcher] to the configOverrides.
+ *
+ * @param labelValue value argument for the label patcher
+ * @param labelName label name argument for the label patcher
+ */
+ fun setAdditionalLabels(
+ labelValue: String,
+ labelName: String
+ ) {
+ val additionalConfigOverrides = mutableListOf<ConfigurationOverride>()
+ resources.forEach {
+ run {
+ val configurationOverride = ConfigurationOverride()
+ configurationOverride.patcher = PatcherDefinition()
+ configurationOverride.patcher.type = "LabelPatcher"
+ configurationOverride.patcher.properties = mutableMapOf("variableName" to labelName)
+ configurationOverride.patcher.resource = it
+ configurationOverride.value = labelValue
+ additionalConfigOverrides.add(configurationOverride)
+ }
+ }
+ execution.configOverrides.addAll(additionalConfigOverrides)
+ }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
index 4fa7fc893cfaf864d935074ff50af8d61f7aac76..2f8c703afa9e826a79f0785abef493d2d448ac74 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
@@ -11,34 +11,34 @@ class LabelPatcher(private val k8sResource: KubernetesResource, val variableName
AbstractPatcher(k8sResource) {
override fun <String> patch(labelValue: String) {
- if(labelValue is kotlin.String){
- when(k8sResource){
+ if (labelValue is kotlin.String) {
+ when (k8sResource) {
is Deployment -> {
- if (k8sResource.metadata.labels == null){
+ if (k8sResource.metadata.labels == null) {
k8sResource.metadata.labels = mutableMapOf()
}
k8sResource.metadata.labels[this.variableName] = labelValue
}
is StatefulSet -> {
- if (k8sResource.metadata.labels == null){
+ if (k8sResource.metadata.labels == null) {
k8sResource.metadata.labels = mutableMapOf()
}
k8sResource.metadata.labels[this.variableName] = labelValue
}
is Service -> {
- if (k8sResource.metadata.labels == null){
+ if (k8sResource.metadata.labels == null) {
k8sResource.metadata.labels = mutableMapOf()
}
k8sResource.metadata.labels[this.variableName] = labelValue
}
is ConfigMap -> {
- if (k8sResource.metadata.labels == null){
+ if (k8sResource.metadata.labels == null) {
k8sResource.metadata.labels = mutableMapOf()
}
k8sResource.metadata.labels[this.variableName] = labelValue
}
- is CustomResource<*,*> -> {
- if (k8sResource.metadata.labels == null){
+ is CustomResource<*, *> -> {
+ if (k8sResource.metadata.labels == null) {
k8sResource.metadata.labels = mutableMapOf()
}
k8sResource.metadata.labels[this.variableName] = labelValue
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
index 65489a96974ad566fe7cbd88cf6ff7fb49135e1d..c617917e6894c3a30779dd4257a96365ded35481 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
@@ -8,13 +8,14 @@ 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 = numSensors.toDouble().pow(Integer.parseInt(value).toDouble())
- val loadGenInstances = (approxNumSensors + loadGenMaxRecords.toDouble() - 1) / loadGenMaxRecords.toDouble()
+ 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/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
index f6a06324e36d7942d3944a492fee263f428376c1..86bb37db3cb9fd0d3bca1690d5eb4e622329a9bc 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
@@ -12,7 +12,8 @@ class NumSensorsLoadGeneratorReplicaPatcher(
override fun <String> patch(value: String) {
if (k8sResource is Deployment) {
if (value is kotlin.String) {
- val loadGenInstances = (Integer.parseInt(value) + loadGenMaxRecords.toInt() - 1) / loadGenMaxRecords.toInt()
+ val loadGenInstances =
+ (Integer.parseInt(value) + loadGenMaxRecords.toInt() - 1) / loadGenMaxRecords.toInt()
this.k8sResource.spec.replicas = loadGenInstances
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt b/theodolite/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt
index d5a6f3821d2688651475625506a78efc6061ab82..6a1f993e2ac327ec242a8a5bafc3e6cc43475710 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt
@@ -21,7 +21,7 @@ class PatcherDefinitionFactory {
* value of the requiredType.
*/
fun createPatcherDefinition(requiredType: String, patcherTypes: List<TypeName>): List<PatcherDefinition> {
- return patcherTypes.firstOrNull() { type -> type.typeName == requiredType }
+ return patcherTypes.firstOrNull { type -> type.typeName == requiredType }
?.patchers ?: throw IllegalArgumentException("typeName $requiredType not found.")
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt b/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
index 3dcddeb7cef06e467fb096ce44ecae4ca95c8094..29723355ce23810c709fe4537242d1fd7e195d25 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
@@ -41,38 +41,38 @@ class PatcherFactory {
)
"NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher(
k8sResource = resource,
- loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"] !!,
- numSensors = patcherDefinition.properties["numSensors"] !!
+ loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"]!!,
+ numSensors = patcherDefinition.properties["numSensors"]!!
)
"NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher(
k8sResource = resource,
- loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"] !!
+ loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"]!!
)
"EnvVarPatcher" -> EnvVarPatcher(
k8sResource = resource,
- container = patcherDefinition.properties["container"] !!,
- variableName = patcherDefinition.properties["variableName"] !!
+ container = patcherDefinition.properties["container"]!!,
+ variableName = patcherDefinition.properties["variableName"]!!
)
"NodeSelectorPatcher" -> NodeSelectorPatcher(
k8sResource = resource,
- variableName = patcherDefinition.properties["variableName"] !!
+ variableName = patcherDefinition.properties["variableName"]!!
)
"ResourceLimitPatcher" -> ResourceLimitPatcher(
k8sResource = resource,
- container = patcherDefinition.properties["container"] !!,
- limitedResource = patcherDefinition.properties["limitedResource"] !!
+ container = patcherDefinition.properties["container"]!!,
+ limitedResource = patcherDefinition.properties["limitedResource"]!!
)
"ResourceRequestPatcher" -> ResourceRequestPatcher(
k8sResource = resource,
- container = patcherDefinition.properties["container"] !!,
- requestedResource = patcherDefinition.properties["requestedResource"] !!
+ container = patcherDefinition.properties["container"]!!,
+ requestedResource = patcherDefinition.properties["requestedResource"]!!
)
"SchedulerNamePatcher" -> SchedulerNamePatcher(
k8sResource = resource
)
"LabelPatcher" -> LabelPatcher(
k8sResource = resource,
- variableName = patcherDefinition.properties["variableName"] !!
+ variableName = patcherDefinition.properties["variableName"]!!
)
"ImagePatcher" -> ImagePatcher(
k8sResource = resource,
@@ -81,8 +81,10 @@ class PatcherFactory {
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." )
+ throw InvalidPatcherConfigurationException(
+ "Could not create patcher with type ${patcherDefinition.type}" +
+ " Probably a required patcher argument was not specified."
+ )
}
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
index 1a6fa35a944d00634ec0607b0bff34f4cb9d9b9c..9dcdffa0407dd4fdaf2d9b0a898bcdf6cebe5a8b 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
@@ -6,6 +6,7 @@ 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 theodolite.util.InvalidPatcherConfigurationException
/**
* The Resource limit [Patcher] set resource limits for deployments and statefulSets.
@@ -33,7 +34,7 @@ class ResourceLimitPatcher(
}
}
else -> {
- throw IllegalArgumentException("ResourceLimitPatcher not applicable for $k8sResource")
+ throw InvalidPatcherConfigurationException("ResourceLimitPatcher not applicable for $k8sResource")
}
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
index 9bf8c3c72f656d326ca3070cd5843778e5cdff42..24cdde40f7f78bd67d115b2dc44f47e180f51ee2 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
@@ -6,6 +6,7 @@ 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 theodolite.util.InvalidPatcherConfigurationException
/**
* The Resource request [Patcher] set resource limits for deployments and statefulSets.
@@ -33,7 +34,7 @@ class ResourceRequestPatcher(
}
}
else -> {
- throw IllegalArgumentException("ResourceRequestPatcher not applicable for $k8sResource")
+ throw InvalidPatcherConfigurationException("ResourceRequestPatcher not applicable for $k8sResource")
}
}
}
diff --git a/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt b/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt
index 0e276d7de4e205a75eb309a71a793e70f7565ea4..639a7c86c641cbdcba361410cf5e25fa56dd795f 100644
--- a/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt
+++ b/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt
@@ -1,5 +1,4 @@
package theodolite.util
-class DeploymentFailedException(message:String): Exception(message) {
-}
\ No newline at end of file
+class DeploymentFailedException(message: String) : Exception(message)
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/util/ExecutionStateComparator.kt b/theodolite/src/main/kotlin/theodolite/util/ExecutionStateComparator.kt
new file mode 100644
index 0000000000000000000000000000000000000000..66ebe12d6505296682744c10c69f182f07d1a16e
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/util/ExecutionStateComparator.kt
@@ -0,0 +1,19 @@
+package theodolite.util
+
+import theodolite.model.crd.ExecutionCRD
+import theodolite.model.crd.States
+
+class ExecutionStateComparator(private val preferredState: States): Comparator<ExecutionCRD> {
+
+ /**
+ * Simple comparator which can be used to order a list of [ExecutionCRD] such that executions with
+ * status [States.RESTART] are before all other executions.
+ */
+ override fun compare(p0: ExecutionCRD, p1: ExecutionCRD): Int {
+ return when {
+ (p0 == null && p1 == null) -> 0
+ (p0.status.executionState == preferredState.value) -> -1
+ else -> 1
+ }
+ }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/util/IOHandler.kt b/theodolite/src/main/kotlin/theodolite/util/IOHandler.kt
index 8d379fcf0543257edafd2e45383a02ba0254563d..57032189412d0937e4d77ddbf4354c78ffcc71a3 100644
--- a/theodolite/src/main/kotlin/theodolite/util/IOHandler.kt
+++ b/theodolite/src/main/kotlin/theodolite/util/IOHandler.kt
@@ -22,7 +22,7 @@ class IOHandler {
var resultsFolder: String = System.getenv("RESULTS_FOLDER") ?: ""
val createResultsFolder = System.getenv("CREATE_RESULTS_FOLDER") ?: "false"
- if (resultsFolder != ""){
+ if (resultsFolder != "") {
logger.info { "RESULT_FOLDER: $resultsFolder" }
val directory = File(resultsFolder)
if (!directory.exists()) {
@@ -35,7 +35,7 @@ class IOHandler {
}
resultsFolder += "/"
}
- return resultsFolder
+ return resultsFolder
}
/**
@@ -70,9 +70,9 @@ class IOHandler {
fun writeToCSVFile(fileURL: String, data: List<List<String>>, columns: List<String>) {
val outputFile = File("$fileURL.csv")
PrintWriter(outputFile).use { pw ->
- pw.println(columns.joinToString(separator=","))
+ pw.println(columns.joinToString(separator = ","))
data.forEach {
- pw.println(it.joinToString(separator=","))
+ pw.println(it.joinToString(separator = ","))
}
}
logger.info { "Wrote CSV file: $fileURL to ${outputFile.absolutePath}." }
@@ -87,7 +87,7 @@ class IOHandler {
fun writeStringToTextFile(fileURL: String, data: String) {
val outputFile = File("$fileURL")
outputFile.printWriter().use {
- it.println(data)
+ it.println(data)
}
logger.info { "Wrote txt file: $fileURL to ${outputFile.absolutePath}." }
}
diff --git a/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt b/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt
index c103ef1f35a1b3ffa56dad50c7cf6c1db51eb57f..e8ecd11d524f5c365149ac0b37c7b985812f8c4b 100644
--- a/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt
+++ b/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt
@@ -1,5 +1,4 @@
package theodolite.util
-class InvalidPatcherConfigurationException(message:String): Exception(message) {
-}
+class InvalidPatcherConfigurationException(message: String) : Exception(message)
diff --git a/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt b/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt
index 846577387c425e920da1c2fca1f972c880e1540a..bf33fcf6104645727a13b92cf3a13d36e04a10c6 100644
--- a/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt
+++ b/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt
@@ -17,8 +17,7 @@ data class PrometheusResponse(
* The data section of the query result contains the information about the resultType and the values itself.
*/
var data: PromData? = null
-)
-{
+) {
/**
* Return the data of the PrometheusResponse as [List] of [List]s of [String]s
* The format of the returned list is: `[[ group, timestamp, value ], [ group, timestamp, value ], ... ]`
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt
index e40b37cfd849ac305fc7f1e03375d016cf7e57db..73a8b9b54813be51937bc17d873ca67dc5ae8724 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt
@@ -73,33 +73,35 @@ class ControllerTest {
@Test
@DisplayName("Check namespaced property of benchmarkCRDClient")
- fun testBenchmarkClientNamespaced(){
+ fun testBenchmarkClientNamespaced() {
val method = controller
.javaClass
.getDeclaredMethod("getBenchmarks")
method.isAccessible = true
method.invoke(controller)
- assert(server
- .lastRequest
- .toString()
- .contains("namespaces")
+ assert(
+ server
+ .lastRequest
+ .toString()
+ .contains("namespaces")
)
}
@Test
@DisplayName("Check namespaced property of executionCRDClient")
- fun testExecutionClientNamespaced(){
+ fun testExecutionClientNamespaced() {
val method = controller
.javaClass
.getDeclaredMethod("getNextExecution")
method.isAccessible = true
method.invoke(controller)
- assert(server
- .lastRequest
- .toString()
- .contains("namespaces")
+ assert(
+ server
+ .lastRequest
+ .toString()
+ .contains("namespaces")
)
}
@@ -133,41 +135,4 @@ class ControllerTest {
gson.toJson(result)
)
}
-
- @Test
- fun setAdditionalLabelsTest() {
- val method = controller
- .javaClass
- .getDeclaredMethod(
- "setAdditionalLabels",
- String::class.java,
- String::class.java,
- List::class.java,
- BenchmarkExecution::class.java
- )
- method.isAccessible = true
-
- method.invoke(
- controller,
- "test-value",
- "test-name",
- listOf("rest-resource.yaml"),
- this.execution
- ) as BenchmarkExecution?
-
- assertEquals(
- "test-name",
- this.execution
- .configOverrides.firstOrNull()
- ?.patcher
- ?.properties
- ?.get("variableName")
- )
- assertEquals(
- "test-value",
- this.execution
- .configOverrides.firstOrNull()
- ?.value
- )
- }
}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt
index 2589319299cfa29f95216033ddc806d002f38663..56d46279e8effe1f0b5bf307cd896ebd5b7eb2ee 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt
@@ -15,6 +15,10 @@ class ExecutionCRDummy(name: String, benchmark: String) {
return this.executionCR
}
+ fun getStatus() : ExecutionStatus {
+ return this.executionState
+ }
+
init {
// configure metadata
executionCR.spec = execution
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt
index a026a349e803a523c5b4725143a5304e3f1b068e..6c94d9734b3d5f6d1cb4901d2b3bc9a473d90e79 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt
@@ -39,7 +39,7 @@ class ExecutionEventHandlerTest {
executionStateHandler = ExecutionStateHandler(client = server.client)
)
- this.factory = operator.getExecutionEventHandler(this.controller,server.client)
+ this.factory = operator.getExecutionEventHandler(this.controller, server.client)
this.stateHandler = TheodoliteOperator().getExecutionStateHandler(client = server.client)
this.executionVersion1 = K8sResourceLoaderFromFile(server.client)
@@ -66,10 +66,11 @@ class ExecutionEventHandlerTest {
factory.startAllRegisteredInformers()
server.lastRequest
// the second request must be namespaced (this is the first `GET` request)
- assert(server
- .lastRequest
- .toString()
- .contains("namespaces")
+ assert(
+ server
+ .lastRequest
+ .toString()
+ .contains("namespaces")
)
}
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt
index 00393dabb1802ecb477c9824352978f1fb98e7e7..b435b47fddcb58d6444e1fc31304bd355a9e7783 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt
@@ -35,23 +35,24 @@ class StateHandlerTest {
fun namespacedTest() {
val handler = ExecutionStateHandler(client = server.client)
handler.getExecutionState("example-execution")
- assert(server
- .lastRequest
- .toString()
- .contains("namespaces")
+ assert(
+ server
+ .lastRequest
+ .toString()
+ .contains("namespaces")
)
}
@Test
@DisplayName("Test empty execution state")
- fun executionWithoutExecutionStatusTest(){
+ fun executionWithoutExecutionStatusTest() {
val handler = ExecutionStateHandler(client = server.client)
assertEquals(States.NO_STATE, handler.getExecutionState("example-execution"))
}
@Test
@DisplayName("Test empty duration state")
- fun executionWithoutDurationStatusTest(){
+ fun executionWithoutDurationStatusTest() {
val handler = ExecutionStateHandler(client = server.client)
assertEquals("-", handler.getDurationState("example-execution"))
}
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/ConfigOverrideModifierTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/ConfigOverrideModifierTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1db1122e1caa5a783159ecaba849b99963e3c2a9
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/ConfigOverrideModifierTest.kt
@@ -0,0 +1,56 @@
+package theodolite.patcher
+
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.KubernetesBenchmark
+import theodolite.execution.operator.BenchmarkCRDummy
+import theodolite.execution.operator.ExecutionCRDummy
+
+@QuarkusTest
+class ConfigOverrideModifierTest {
+ private var execution = BenchmarkExecution()
+ private var benchmark = KubernetesBenchmark()
+
+
+ @BeforeEach
+ fun setup() {
+ val execution1 = ExecutionCRDummy(name = "matching-execution", benchmark = "Test-Benchmark")
+ val benchmark1 = BenchmarkCRDummy(name = "Test-Benchmark")
+
+ this.execution = execution1.getCR().spec
+ this.benchmark = benchmark1.getCR().spec
+ }
+
+
+ @Test
+ fun setAdditionalLabelsTest() {
+
+ val modifier = ConfigOverrideModifier(
+ execution = this.execution,
+ resources = listOf("test-resource.yaml")
+ )
+
+ modifier.setAdditionalLabels(
+ labelName = "test-name",
+ labelValue = "test-value"
+ )
+
+ Assertions.assertEquals(
+ "test-name",
+ this.execution
+ .configOverrides.firstOrNull()
+ ?.patcher
+ ?.properties
+ ?.get("variableName")
+ )
+ Assertions.assertEquals(
+ "test-value",
+ this.execution
+ .configOverrides.firstOrNull()
+ ?.value
+ )
+ }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/util/ExecutionStateComparatorTest.kt b/theodolite/src/test/kotlin/theodolite/util/ExecutionStateComparatorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..eec029f3878171eb2fd502bf68f549cfce793f23
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/util/ExecutionStateComparatorTest.kt
@@ -0,0 +1,33 @@
+package theodolite.util
+
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.Rule
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import theodolite.execution.operator.ExecutionCRDummy
+import theodolite.model.crd.ExecutionCRD
+import theodolite.model.crd.States
+
+
+@QuarkusTest
+class ExecutionStateComparatorTest {
+
+ @Test
+ fun testCompare() {
+ val comparator = ExecutionStateComparator(States.RESTART)
+ val execution1 = ExecutionCRDummy("dummy1", "default-benchmark")
+ val execution2 = ExecutionCRDummy("dummy2", "default-benchmark")
+ execution1.getStatus().executionState = States.RESTART.value
+ execution2.getStatus().executionState = States.PENDING.value
+ val list = listOf(execution2.getCR(), execution1.getCR())
+
+
+ assertEquals(
+ list.reversed(),
+ list.sortedWith(comparator)
+ )
+ }
+
+}
\ No newline at end of file