diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 01630912c52ccc728870d72c33a8f02cdf7c2c7f..f2f1bd6263e917ff4c9c78f7d851b61cacc6c57f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -307,11 +307,23 @@ deploy-theodolite:
 
 # Theodolite SLO Checker: Lag Trend
 
+test-slo-checker-lag-trend:
+  stage: test
+  image: python:3.7-slim
+  tags:
+    - exec-docker
+  script:
+    - cd slope-evaluator
+    - pip install -r requirements.txt
+    - cd app
+    - python -m unittest
+
 deploy-slo-checker-lag-trend:
   stage: deploy
   extends:
     - .dind
-  needs: []
+  needs:
+    - test-slo-checker-lag-trend
   script:
     - DOCKER_TAG_NAME=$(echo $CI_COMMIT_REF_SLUG- | sed 's/^master-$//')
     - docker build --pull -t theodolite-slo-checker-lag-trend slope-evaluator
diff --git a/execution/helm/.gitignore b/execution/helm/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..80bf7fc709ac6d08e703fe9f24d7d5776e26830e
--- /dev/null
+++ b/execution/helm/.gitignore
@@ -0,0 +1 @@
+charts
\ No newline at end of file
diff --git a/execution/helm/templates/grafana/dashboard-config-map.yaml b/execution/helm/templates/grafana/dashboard-config-map.yaml
index 1125d7833cc62e78c049436f38b854d926e2a216..41365e5efefaddc92a9f2f25f867a9d895e4ca3d 100644
--- a/execution/helm/templates/grafana/dashboard-config-map.yaml
+++ b/execution/helm/templates/grafana/dashboard-config-map.yaml
@@ -253,7 +253,7 @@ data:
         "steppedLine": false,
         "targets": [
           {
-            "expr": "sum by(group, topic) (kafka_consumergroup_group_lag > 0)",
+            "expr": "sum by(group, topic) (kafka_consumergroup_group_lag >= 0)",
             "format": "time_series",
             "intervalFactor": 1,
             "legendFormat": "{{topic}}",
@@ -436,7 +436,7 @@ data:
         "steppedLine": false,
         "targets": [
           {
-            "expr": "sum by(group,topic) (kafka_consumergroup_group_offset > 0)",
+            "expr": "sum by(group,topic) (kafka_consumergroup_group_offset >= 0)",
             "format": "time_series",
             "intervalFactor": 1,
             "legendFormat": "{{topic}}",
@@ -527,7 +527,7 @@ data:
         "steppedLine": false,
         "targets": [
           {
-            "expr": "count by(group,topic) (kafka_consumergroup_group_offset > 0)",
+            "expr": "count by(group,topic) (kafka_consumergroup_group_offset >= 0)",
             "format": "time_series",
             "intervalFactor": 1,
             "legendFormat": "{{topic}}",
@@ -892,7 +892,7 @@ data:
         "steppedLine": false,
         "targets": [
           {
-            "expr": "sum by(group) (kafka_consumergroup_group_lag > 0)",
+            "expr": "sum by(group) (kafka_consumergroup_group_lag >= 0)",
             "format": "time_series",
             "intervalFactor": 1,
             "legendFormat": "total lag",
diff --git a/execution/helm/templates/theodolite/crd-benchmark.yaml b/execution/helm/templates/theodolite/crd-benchmark.yaml
index 9d7468b490fa2f2a6cf829bdcafab8c4bd6fc5bf..319eee18cee87d12cd7051e5fc3414f99c8d8a30 100644
--- a/execution/helm/templates/theodolite/crd-benchmark.yaml
+++ b/execution/helm/templates/theodolite/crd-benchmark.yaml
@@ -1,15 +1,121 @@
 {{- if .Values.benchmarkCRD.create -}}
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   name: benchmarks.theodolite.com
 spec:
   group: theodolite.com
-  version: v1alpha1
   names:
     kind: benchmark
     plural: benchmarks
+    shortNames:
+      - bench
+  versions:
+  - name: v1
+    served: true
+    storage: true
+    schema:
+      openAPIV3Schema:
+        type: object
+        required: ["spec"]
+        properties:
+          spec:
+            type: object
+            required: []
+            properties:
+              name:
+                type: string
+              appResource:
+                type: array
+                minItems: 1
+                items:
+                  type: string
+              loadGenResource:
+                type: array
+                minItems: 1
+                items:
+                  type: string
+              resourceTypes:
+                type: array
+                minItems: 1
+                items:
+                  type: object
+                  properties:
+                    typeName:
+                      type: string
+                    patchers:
+                      type: array
+                      minItems: 1
+                      items:
+                        type: object
+                        properties:
+                          type:
+                            type: string
+                            default: ""
+                          resource:
+                            type: string
+                            default: ""
+                          config:
+                            type: object
+                            additionalProperties: true
+                            x-kubernetes-map-type: "granular"
+                            default: 
+                              "": ""
+              loadTypes:
+                type: array
+                minItems: 1
+                items:
+                  type: object
+                  properties:
+                    typeName:
+                      type: string
+                    patchers:
+                      type: array
+                      minItems: 1
+                      items:
+                        type: object
+                        properties:
+                          type:
+                            type: string
+                            default: ""
+                          resource:
+                            type: string
+                            default: ""
+                          config:
+                            type: object
+                            additionalProperties: true
+                            x-kubernetes-map-type: "granular"
+                            default: 
+                              "": ""
+              kafkaConfig:
+                type: object
+                properties:
+                  bootstrapServer:
+                    type: string
+                  topics:
+                    type: array
+                    minItems: 1
+                    items:
+                      type: object
+                      required: []
+                      properties:
+                        name:
+                          type: string
+                          default: ""
+                        numPartitions:
+                          type: integer
+                          default: 0
+                        replicationFactor:
+                          type: integer
+                          default: 0
+                        removeOnly:
+                          type: boolean
+                          default: false
+    additionalPrinterColumns:
+    - name: Age
+      type: date
+      jsonPath: .metadata.creationTimestamp
+    subresources:
+      status: {}
   scope: Namespaced
-  subresources:
-    status: {}
 {{- end }}
\ No newline at end of file
diff --git a/execution/helm/templates/theodolite/crd-execution.yaml b/execution/helm/templates/theodolite/crd-execution.yaml
index 73b58397b8c1fc15ffef5da74e8f1dbdabaa3a30..41ba1b0b5b19b53d9b7caec48241285edf4ba396 100644
--- a/execution/helm/templates/theodolite/crd-execution.yaml
+++ b/execution/helm/templates/theodolite/crd-execution.yaml
@@ -1,15 +1,129 @@
-{{- if .Values.executionCRD.create -}}
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   name: executions.theodolite.com
 spec:
   group: theodolite.com
-  version: v1alpha1
   names:
     kind: execution
     plural: executions
-  scope: Namespaced
-  subresources:
-    status: {}
-{{- end }}
\ No newline at end of file
+    shortNames:
+      - exec
+  versions:
+  - name: v1
+    served: true
+    storage: true
+    schema:
+      openAPIV3Schema:
+        type: object
+        required: ["spec"]
+        properties:
+          spec:
+            type: object
+            required: ["benchmark", "load", "resources", "slos", "execution", "configOverrides"]
+            properties:
+              name:
+                type: string
+                default: ""
+              benchmark:
+                type: string
+              load: # definition of the load dimension
+                type: object
+                required: ["loadType", "loadValues"]
+                properties:
+                  loadType:
+                   type: string
+                  loadValues:
+                    type: array
+                    items:
+                      type: integer
+              resources: # definition of the resource dimension
+                type: object
+                required: ["resourceType", "resourceValues"]
+                properties:
+                  resourceType:
+                    type: string
+                  resourceValues:
+                    type: array
+                    items:
+                      type: integer
+              slos: # def of service level objectives
+                type: array
+                items:
+                  type: object
+                  required: ["sloType", "threshold", "prometheusUrl", "externalSloUrl", "offset", "warmup"]
+                  properties:
+                    sloType:
+                      type: string
+                    threshold:
+                      type: integer
+                    prometheusUrl:
+                      type: string
+                    externalSloUrl:
+                      type: string
+                    offset:
+                      type: integer
+                    warmup:
+                      type: integer
+              execution: # def execution config
+                type: object
+                required: ["strategy", "duration", "repetitions", "restrictions"]
+                properties:
+                  strategy:
+                    type: string
+                  duration:
+                    type: integer
+                  repetitions:
+                    type: integer
+                  loadGenerationDelay:
+                    type: integer
+                  restrictions:
+                    type: array
+                    items:
+                      type: string
+              configOverrides:
+                type: array
+                items:
+                  type: object
+                  properties:
+                    patcher:
+                      type: object
+                      properties:
+                        type:
+                          type: string
+                          default: ""
+                        resource:
+                          type: string
+                          default: ""
+                        config:
+                            type: object
+                            additionalProperties: true
+                            x-kubernetes-map-type: "granular"
+                            default: 
+                              "": ""
+                    value:
+                      type: string
+          status:
+            type: object
+            properties:
+              executionState:
+                description: ""
+                type: string
+              executionDuration:
+                description: "Duration of the execution in seconds"
+                type: string
+    additionalPrinterColumns:
+    - name: STATUS
+      type: string
+      description: State of the execution
+      jsonPath: .status.executionState
+    - name: Duration
+      type: string
+      description: Duration of the execution
+      jsonPath: .status.executionDuration
+    - name: Age
+      type: date
+      jsonPath: .metadata.creationTimestamp
+    subresources:
+      status: {}
+  scope: Namespaced
\ No newline at end of file
diff --git a/execution/helm/templates/theodolite/role.yaml b/execution/helm/templates/theodolite/role.yaml
index ee699a5b861c64e355ca2ba44330a7d600756b77..630a84c0491328a9bb1900c1f99a8f4643020e17 100644
--- a/execution/helm/templates/theodolite/role.yaml
+++ b/execution/helm/templates/theodolite/role.yaml
@@ -56,5 +56,14 @@ rules:
     - watch
     - update
     - patch
+  - apiGroups:
+    - coordination.k8s.io
+    resources:
+    - leases
+    verbs:
+    - delete
+    - get
+    - create
+    - update
   {{- end }}
 {{- end }}
\ No newline at end of file
diff --git a/execution/helm/values.yaml b/execution/helm/values.yaml
index b4f2ffdea14c4c98a5b23b8f15056880a190e1a4..d245e37e6f50d3874a1a5c06bd0156009777a999 100644
--- a/execution/helm/values.yaml
+++ b/execution/helm/values.yaml
@@ -25,8 +25,16 @@ grafana:
   adminUser: admin
   adminPassword: admin
   grafana.ini:
+    #org_name: Theodolite
+    auth.anonymous:
+      # enable anonymous access
+      enabled: true
+      org_role: Admin # Role for unauthenticated users, other valid values are `Viewer`, `Editor` and `Admin`
     users:
       default_theme: light
+    #dashboards: # the following doesn't work but is planed
+      # Path to the default home dashboard. If this value is empty, then Grafana uses StaticRootPath + "dashboards/home.json"
+      #default_home_dashboard_path: "/tmp/dashboards/k8s-dashboard.json"
   ## Sidecars that collect the configmaps with specified label and stores the included files them into the respective folders
   ## Requires at least Grafana 5 to work and can't be used together with parameters dashboardProviders, datasources and dashboards
   sidecar:
diff --git a/execution/infrastructure/kubernetes/rbac/role.yaml b/execution/infrastructure/kubernetes/rbac/role.yaml
index a21fd554f0f56b3955e9a9b6cf4bf95442b5d7af..e45814eedacd30715075f66e520f9f9e6bfc42ad 100644
--- a/execution/infrastructure/kubernetes/rbac/role.yaml
+++ b/execution/infrastructure/kubernetes/rbac/role.yaml
@@ -52,4 +52,12 @@ rules:
     - watch
     - update
     - patch
-    
+  - apiGroups:
+    - coordination.k8s.io
+    resources:
+    - leases
+    verbs:
+    - delete
+    - get
+    - create
+    - update
\ No newline at end of file
diff --git a/slope-evaluator/README.md b/slope-evaluator/README.md
index 12e8a61783532efce9e8722f500cf5ff880bace7..cd9e6820ed46452ce44d57d0c7e5cd5ae05e5a3b 100644
--- a/slope-evaluator/README.md
+++ b/slope-evaluator/README.md
@@ -5,7 +5,7 @@
 For development:
 
 ```sh
-uvicorn main:app --reload
+uvicorn main:app --reload # run this command inside the app/ folder
 ```
 
 ## Build the docker image:
@@ -32,7 +32,7 @@ The running webserver provides a REST API with the following route:
 * /evaluate-slope
     * Method: POST
     * Body:
-        * total_lag
+        * total_lags
         * threshold
         * warmup
 
@@ -40,14 +40,16 @@ The body of the request must be a JSON string that satisfies the following condi
 
 * **total_lag**: This property is based on the [Range Vector type](https://www.prometheus.io/docs/prometheus/latest/querying/api/#range-vectors) from Prometheus and must have the following JSON structure:
     ```
-        {
-            "metric": {
-                "group": "<label_value>"
-            },
-            "values": [
-                [
-                    <unix_timestamp>,
-                    "<sample_value>"
+        { 
+            [
+                "metric": {
+                    "group": "<label_value>"
+                },
+                "values": [
+                    [
+                        <unix_timestamp>,
+                        "<sample_value>"
+                    ]
                 ]
             ]
         }
diff --git a/slope-evaluator/app/main.py b/slope-evaluator/app/main.py
index 5995a1175f781c4eb51ab3d3083a665fbc02d6fd..6f6788f0ca84b7710be5b509ca4f0641047e963d 100644
--- a/slope-evaluator/app/main.py
+++ b/slope-evaluator/app/main.py
@@ -5,6 +5,7 @@ import os
 import pandas as pd
 import json
 import sys
+from statistics import median
 
 app = FastAPI()
 
@@ -20,7 +21,7 @@ elif os.getenv('LOG_LEVEL') == 'WARNING':
 elif os.getenv('LOG_LEVEL') == 'DEBUG':
     logger.setLevel(logging.DEBUG)
 
-def execute(results, threshold, warmup):
+def calculate_slope_trend(results, warmup):
     d = []
     for result in results:
         group = result['metric']['group']
@@ -39,13 +40,16 @@ def execute(results, threshold, warmup):
         logger.error('Mark this subexperiment as not successful and continue benchmark.')
         return False
 
-    result = trend_slope < threshold
-    logger.info("Computed lag trend slope is '%s'. Result is: %s", trend_slope, result)
-    return result
+    logger.info("Computed lag trend slope is '%s'", trend_slope)
+    return trend_slope
+
+def check_service_level_objective(results, threshold):
+    return median(results) < threshold
 
 @app.post("/evaluate-slope",response_model=bool)
 async def evaluate_slope(request: Request):
     data = json.loads(await request.body())
-    return execute(data['total_lag'], data['threshold'], data['warmup'])
+    results = [calculate_slope_trend(total_lag, data['warmup']) for total_lag in data['total_lags']]
+    return check_service_level_objective(results=results, threshold=data["threshold"])
 
-logger.info("Slope evaluator is online")
\ No newline at end of file
+logger.info("SLO evaluator is online")
\ No newline at end of file
diff --git a/slope-evaluator/app/test.py b/slope-evaluator/app/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b165ea479bb9a552edaba7692df4fd4ef3f4ab4
--- /dev/null
+++ b/slope-evaluator/app/test.py
@@ -0,0 +1,30 @@
+import unittest
+from main import app, check_service_level_objective
+import json
+from fastapi.testclient import TestClient
+
+class TestSloEvaluation(unittest.TestCase):
+    client = TestClient(app)
+
+    def test_1_rep(self):
+        with open('../resources/test-1-rep-success.json') as json_file:
+            data = json.load(json_file)
+            response = self.client.post("/evaluate-slope", json=data)
+            self.assertEquals(response.json(), True)
+
+    def test_3_rep(self):
+        with open('../resources/test-3-rep-success.json') as json_file:
+            data = json.load(json_file)
+            response = self.client.post("/evaluate-slope", json=data)
+            self.assertEquals(response.json(), True)
+        
+    def test_check_service_level_objective(self):
+        list = [1,2,3,4]
+        self.assertEquals(check_service_level_objective(list, 2), False)
+        self.assertEquals(check_service_level_objective(list, 3), True)
+        list = [1,2,3,4,5]
+        self.assertEquals(check_service_level_objective(list, 2), False)
+        self.assertEquals(check_service_level_objective(list, 4), True)
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/slope-evaluator/requirements.txt b/slope-evaluator/requirements.txt
index ca77b6c891136b1388aaf56c5ae269d6ee4b5729..670815f35b18361951a2fa7b2142eee6bc86b01d 100644
--- a/slope-evaluator/requirements.txt
+++ b/slope-evaluator/requirements.txt
@@ -1,3 +1,5 @@
 fastapi==0.55.1
 scikit-learn==0.20.3
 pandas==1.0.3
+uvicorn
+requests
diff --git a/slope-evaluator/resources/test-1-rep-success.json b/slope-evaluator/resources/test-1-rep-success.json
new file mode 100644
index 0000000000000000000000000000000000000000..9e315c707be7b2a874c58fcb1093aa86f7676560
--- /dev/null
+++ b/slope-evaluator/resources/test-1-rep-success.json
@@ -0,0 +1,139 @@
+{
+    "total_lags": [
+        [
+            {
+                "metric": {
+                    "group": "theodolite-uc1-application-0.0.1"
+                },
+                "values": [
+                    [
+                        1.621008960827E9,
+                        "234"
+                    ],
+                    [
+                        1.621008965827E9,
+                        "234"
+                    ],
+                    [
+                        1.621008970827E9,
+                        "234"
+                    ],
+                    [
+                        1.621008975827E9,
+                        "719"
+                    ],
+                    [
+                        1.621008980827E9,
+                        "719"
+                    ],
+                    [
+                        1.621008985827E9,
+                        "719"
+                    ],
+                    [
+                        1.621008990827E9,
+                        "1026"
+                    ],
+                    [
+                        1.621008995827E9,
+                        "1026"
+                    ],
+                    [
+                        1.621009000827E9,
+                        "1026"
+                    ],
+                    [
+                        1.621009005827E9,
+                        "534"
+                    ],
+                    [
+                        1.621009010827E9,
+                        "534"
+                    ],
+                    [
+                        1.621009015827E9,
+                        "534"
+                    ],
+                    [
+                        1.621009020827E9,
+                        "943"
+                    ],
+                    [
+                        1.621009025827E9,
+                        "943"
+                    ],
+                    [
+                        1.621009030827E9,
+                        "943"
+                    ],
+                    [
+                        1.621009035827E9,
+                        "66"
+                    ],
+                    [
+                        1.621009040827E9,
+                        "66"
+                    ],
+                    [
+                        1.621009045827E9,
+                        "66"
+                    ],
+                    [
+                        1.621009050827E9,
+                        "841"
+                    ],
+                    [
+                        1.621009055827E9,
+                        "841"
+                    ],
+                    [
+                        1.621009060827E9,
+                        "841"
+                    ],
+                    [
+                        1.621009065827E9,
+                        "405"
+                    ],
+                    [
+                        1.621009070827E9,
+                        "405"
+                    ],
+                    [
+                        1.621009075827E9,
+                        "405"
+                    ],
+                    [
+                        1.621009080827E9,
+                        "201"
+                    ],
+                    [
+                        1.621009085827E9,
+                        "201"
+                    ],
+                    [
+                        1.621009090827E9,
+                        "201"
+                    ],
+                    [
+                        1.621009095827E9,
+                        "227"
+                    ],
+                    [
+                        1.621009100827E9,
+                        "227"
+                    ],
+                    [
+                        1.621009105827E9,
+                        "227"
+                    ],
+                    [
+                        1.621009110827E9,
+                        "943"
+                    ]
+                ]
+            }
+        ]
+    ],
+    "threshold": 2000,
+    "warmup": 0
+}
\ No newline at end of file
diff --git a/slope-evaluator/resources/test-3-rep-success.json b/slope-evaluator/resources/test-3-rep-success.json
new file mode 100644
index 0000000000000000000000000000000000000000..485966cba40f01e4a646e626914510ba49b707bc
--- /dev/null
+++ b/slope-evaluator/resources/test-3-rep-success.json
@@ -0,0 +1,289 @@
+{
+    "total_lags": [
+        [
+            {
+                "metric": {
+                    "group": "theodolite-uc1-application-0.0.1"
+                },
+                "values": [
+                    [
+                        1.621012384232E9,
+                        "6073"
+                    ],
+                    [
+                        1.621012389232E9,
+                        "6073"
+                    ],
+                    [
+                        1.621012394232E9,
+                        "6073"
+                    ],
+                    [
+                        1.621012399232E9,
+                        "227"
+                    ],
+                    [
+                        1.621012404232E9,
+                        "227"
+                    ],
+                    [
+                        1.621012409232E9,
+                        "227"
+                    ],
+                    [
+                        1.621012414232E9,
+                        "987"
+                    ],
+                    [
+                        1.621012419232E9,
+                        "987"
+                    ],
+                    [
+                        1.621012424232E9,
+                        "987"
+                    ],
+                    [
+                        1.621012429232E9,
+                        "100"
+                    ],
+                    [
+                        1.621012434232E9,
+                        "100"
+                    ],
+                    [
+                        1.621012439232E9,
+                        "100"
+                    ],
+                    [
+                        1.621012444232E9,
+                        "959"
+                    ],
+                    [
+                        1.621012449232E9,
+                        "959"
+                    ],
+                    [
+                        1.621012454232E9,
+                        "959"
+                    ],
+                    [
+                        1.621012459232E9,
+                        "625"
+                    ],
+                    [
+                        1.621012464232E9,
+                        "625"
+                    ],
+                    [
+                        1.621012469232E9,
+                        "625"
+                    ],
+                    [
+                        1.621012474232E9,
+                        "683"
+                    ],
+                    [
+                        1.621012479232E9,
+                        "683"
+                    ],
+                    [
+                        1.621012484232E9,
+                        "683"
+                    ],
+                    [
+                        1.621012489232E9,
+                        "156"
+                    ]
+                ]
+            }
+        ],
+        [
+            {
+                "metric": {
+                    "group": "theodolite-uc1-application-0.0.1"
+                },
+                "values": [
+                    [
+                        1.621012545211E9,
+                        "446"
+                    ],
+                    [
+                        1.621012550211E9,
+                        "446"
+                    ],
+                    [
+                        1.621012555211E9,
+                        "446"
+                    ],
+                    [
+                        1.621012560211E9,
+                        "801"
+                    ],
+                    [
+                        1.621012565211E9,
+                        "801"
+                    ],
+                    [
+                        1.621012570211E9,
+                        "801"
+                    ],
+                    [
+                        1.621012575211E9,
+                        "773"
+                    ],
+                    [
+                        1.621012580211E9,
+                        "773"
+                    ],
+                    [
+                        1.621012585211E9,
+                        "773"
+                    ],
+                    [
+                        1.621012590211E9,
+                        "509"
+                    ],
+                    [
+                        1.621012595211E9,
+                        "509"
+                    ],
+                    [
+                        1.621012600211E9,
+                        "509"
+                    ],
+                    [
+                        1.621012605211E9,
+                        "736"
+                    ],
+                    [
+                        1.621012610211E9,
+                        "736"
+                    ],
+                    [
+                        1.621012615211E9,
+                        "736"
+                    ],
+                    [
+                        1.621012620211E9,
+                        "903"
+                    ],
+                    [
+                        1.621012625211E9,
+                        "903"
+                    ],
+                    [
+                        1.621012630211E9,
+                        "903"
+                    ],
+                    [
+                        1.621012635211E9,
+                        "512"
+                    ],
+                    [
+                        1.621012640211E9,
+                        "512"
+                    ],
+                    [
+                        1.621012645211E9,
+                        "512"
+                    ]
+                ]
+            }
+        ],
+        [
+            {
+                "metric": {
+                    "group": "theodolite-uc1-application-0.0.1"
+                },
+                "values": [
+                    [
+                        1.621012700748E9,
+                        "6484"
+                    ],
+                    [
+                        1.621012705748E9,
+                        "6484"
+                    ],
+                    [
+                        1.621012710748E9,
+                        "6484"
+                    ],
+                    [
+                        1.621012715748E9,
+                        "505"
+                    ],
+                    [
+                        1.621012720748E9,
+                        "505"
+                    ],
+                    [
+                        1.621012725748E9,
+                        "505"
+                    ],
+                    [
+                        1.621012730748E9,
+                        "103"
+                    ],
+                    [
+                        1.621012735748E9,
+                        "103"
+                    ],
+                    [
+                        1.621012740748E9,
+                        "103"
+                    ],
+                    [
+                        1.621012745748E9,
+                        "201"
+                    ],
+                    [
+                        1.621012750748E9,
+                        "201"
+                    ],
+                    [
+                        1.621012755748E9,
+                        "201"
+                    ],
+                    [
+                        1.621012760748E9,
+                        "965"
+                    ],
+                    [
+                        1.621012765748E9,
+                        "965"
+                    ],
+                    [
+                        1.621012770748E9,
+                        "965"
+                    ],
+                    [
+                        1.621012775748E9,
+                        "876"
+                    ],
+                    [
+                        1.621012780748E9,
+                        "876"
+                    ],
+                    [
+                        1.621012785748E9,
+                        "876"
+                    ],
+                    [
+                        1.621012790748E9,
+                        "380"
+                    ],
+                    [
+                        1.621012795748E9,
+                        "380"
+                    ],
+                    [
+                        1.621012800748E9,
+                        "380"
+                    ]
+                ]
+            }
+        ]
+    ],
+    "threshold": 2000,
+    "warmup": 0
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/build.gradle b/theodolite-quarkus/build.gradle
index 8b61bf506dd241c5b0d4e75b1357ef3fd5966135..8c0a13d1f24cfde01c8604285c49d3f48fe6a3b7 100644
--- a/theodolite-quarkus/build.gradle
+++ b/theodolite-quarkus/build.gradle
@@ -25,9 +25,12 @@ dependencies {
     implementation 'io.quarkus:quarkus-kubernetes-client'
     implementation 'org.apache.kafka:kafka-clients:2.7.0'
     implementation 'khttp:khttp:1.0.0'
+    compile 'junit:junit:4.12'
+
 
     testImplementation 'io.quarkus:quarkus-junit5'
     testImplementation 'io.rest-assured:rest-assured'
+    testImplementation 'org.junit-pioneer:junit-pioneer:1.4.0'
 }
 
 group 'theodolite'
diff --git a/theodolite-quarkus/config/README.md b/theodolite-quarkus/config/README.md
index 4f53d87ba9ac12099091faa315913cf93ed62bb7..23337d77375ebba8f624e7a11f714502fe3d5e67 100644
--- a/theodolite-quarkus/config/README.md
+++ b/theodolite-quarkus/config/README.md
@@ -19,14 +19,16 @@ resourceTypes:
     patchers:
       - type: String
         resources: String
-        <Patcher Arguments> ...
+        properties:
+          <Patcher Arguments> ...
       ...
 loadTypes:
   - typeName: String
   patchers:
     - type: String
       resources: String
-      <Patcher Arguments> ...
+      properties:
+        <Patcher Arguments> ...
     ...
 kafkaConfig:
   bootstrapServer: String
@@ -49,7 +51,7 @@ The properties have the following definitions:
     * **patchers**: List of [patchers](#Patchers) used to scale this resource type. Each patcher has the following structure:
         * **type**: Type of the [patcher](#Patchers). The concrete types can be looked up in the list of [patchers](#Patchers). 
         * **resources**: Specifies the Kubernetes resource to be patched.
-        * **Patcher Arguments**: (Optional) Patcher specific additional arguments.
+        *  **properties**: *Patcher Arguments*: (Optional) Patcher specific additional arguments.
 * **loadTypes**: A list of load types that can be scaled for this *benchmark*. For each load type the concrete values are defined in the *execution* object. Each load type has the following structure:
     * **typeName**: Name of the load type.
     * **patchers**: List of patchers used to scale * **resourceTypes**: A list of resource types that can be scaled for this *benchmark*. For each resource type the concrete values are defined in the *execution* resource object.Each resource type has the following structure:
@@ -57,7 +59,7 @@ The properties have the following definitions:
     * **patchers**: List of patchers used to scale this resource type. Each patcher has the following structure:
         * **type**: Type of the Patcher. The concrete types can be looked up in the list of patchers. 
         * **resources**: Specifies the Kubernetes resource to be patched.
-        * **Patcher Arguments**: (Optional) Patcher specific additional arguments.
+        * **properties**: *Patcher Arguments*: (Optional) Patcher specific additional arguments as Map<String, String>.
 * **kafkaConfig**: Contains the Kafka configuration.
     * **bootstrapServers**: The bootstrap servers connection string.
     * **topics**: List of topics to be created for each [experiment](#Experiment). Alternative theodolite offers the possibility to remove certain topics after each experiment.
@@ -105,7 +107,8 @@ configurationOverrides:
   - patcher:
       type: String
       resource: String
-      <Patcher Arguments> ...
+      properties:
+        <Patcher Arguments> ...
   ...
 ```
 
@@ -136,7 +139,7 @@ The properties have the following definitions:
   * **patcher**: Patcher used to patch a resource. Each patcher has the following structure:
         * **type**: Type of the Patcher. The concrete types can be looked up in the list of patchers. 
         * **resources**: Specifies the Kubernetes resource to be patched.
-        * **Patcher Arguments**: (Optional) Patcher specific additional arguments.
+        * **properties**: *Patcher Arguments*: (Optional) Patcher specific additional arguments.
 
 ## Patchers
 
@@ -159,19 +162,22 @@ The properties have the following definitions:
 * **EnvVarPatcher**: Allows to modify the value of an environment variable for a container in a kubernetes deployment. 
   * **type**: "EnvVarPatcher"
   * **resource**: "uc1-load-generator-deployment.yaml"
-  * **container**: "workload-generator"
-  * **variableName**: "NUM_SENSORS"
+  * **properties**:
+    * container: "workload-generator"
+    * variableName: "NUM_SENSORS"
 
 * **NodeSelectorPatcher**: Changes the node selection field in kubernetes resources.
   * **type**: "NodeSelectorPatcher"
   * **resource**: "uc1-load-generator-deployment.yaml"
-  * **variableName**: "env"
+  * **properties**:
+    * variableName: "env"
   * **value**: "prod"
 
 * **ResourceLimitPatcher**: Changes the resource limit for a kubernetes resource.
   * **resource**: "uc1-kstreams-deployment.yaml"
-  * **container**: "uc-application"
-  * **variableName**: "cpu" or "memory"
+  * **properties**:
+    * container: "uc-application"
+    * variableName: "cpu" or "memory"
   * **value**:"1000m" or "2Gi"
   
 * **SchedulerNamePatcher**: Changes the sheduler for kubernetes resources.
@@ -182,7 +188,8 @@ The properties have the following definitions:
 * **ImagePatcher**: Changes the image of a kubernetes resource. Currently not fully implemented.
   * **type**: "ImagePatcher"
   * **resource**: "uc1-kstreams-deployment.yaml"
-  * **container**: "uc-application"
+  * **properties**:
+    * container: "uc-application"
   * **value**: "dockerhubrepo/imagename"
 
 
diff --git a/theodolite-quarkus/config/example-benchmark-yaml-resource.yaml b/theodolite-quarkus/config/example-benchmark-yaml-resource.yaml
index cdc2122d9e6b568f1a75b0d55eff8a0af6450983..623df71121b11b670584a83e153b4dd2962525e7 100644
--- a/theodolite-quarkus/config/example-benchmark-yaml-resource.yaml
+++ b/theodolite-quarkus/config/example-benchmark-yaml-resource.yaml
@@ -17,10 +17,13 @@ loadTypes:
     patchers:
       - type: "EnvVarPatcher"
         resource: "uc1-load-generator-deployment.yaml"
-        container: "workload-generator"
-        variableName: "NUM_SENSORS"
+        properties:
+          variableName: "NUM_SENSORS"
+          container: "workload-generator"
       - type: "NumSensorsLoadGeneratorReplicaPatcher"
         resource: "uc1-load-generator-deployment.yaml"
+        properties:
+          loadGenMaxRecords: "15000"
 kafkaConfig:
   bootstrapServer: "localhost:31290"
   topics:
diff --git a/theodolite-quarkus/config/example-execution-yaml-resource.yaml b/theodolite-quarkus/config/example-execution-yaml-resource.yaml
index e0b327a022099410fea8028fb5d37fee5672a857..e46a6cf417442b851650fe9699f73e1367dcc794 100644
--- a/theodolite-quarkus/config/example-execution-yaml-resource.yaml
+++ b/theodolite-quarkus/config/example-execution-yaml-resource.yaml
@@ -20,29 +20,33 @@ execution:
   loadGenerationDelay: 30 # in seconds, optional field, default is 0 seconds
   restrictions:
     - "LowerBound"
-configOverrides: []
-#  - patcher:
-#      type: "NodeSelectorPatcher"
-#      resource: "uc1-load-generator-deployment.yaml"
-#      variableName: "env"
-#    value: "prod"
-#  - patcher:
-#      type: "NodeSelectorPatcher"
-#      resource: "uc1-kstreams-deployment.yaml"
-#      variableName: "env"
-#    value: "prod"
-#  - patcher:
-#      type: "ResourceLimitPatcher"
-#      resource: "uc1-kstreams-deployment.yaml"
-#      container: "uc-application"
-#      variableName: "cpu"
-#    value: "1000m"
-#  - patcher:
-#      type: "ResourceLimitPatcher"
-#      resource: "uc1-kstreams-deployment.yaml"
-#      container: "uc-application"
-#      variableName: "memory"
-#    value: "2Gi"
+configOverrides:
+  - patcher:
+      type: "NodeSelectorPatcher"
+      resource: "uc1-load-generator-deployment.yaml"
+      properties:
+        variableName: "env"
+    value: "prod"
+  - patcher:
+      type: "NodeSelectorPatcher"
+      resource: "uc1-kstreams-deployment.yaml"
+      properties:
+        variableName: "env"
+    value: "prod"
+  - patcher:
+      type: "ResourceLimitPatcher"
+      resource: "uc1-kstreams-deployment.yaml"
+      properties:
+        container: "uc-application"
+        limitedResource: "cpu"
+    value: "1000m"
+  - patcher:
+      type: "ResourceLimitPatcher"
+      resource: "uc1-kstreams-deployment.yaml"
+      properties:
+        container: "uc-application"
+        limitedResource: "memory"
+    value: "2Gi"
 #  - patcher:
 #      type: "SchedulerNamePatcher"
 #      resource: "uc1-kstreams-deployment.yaml"
diff --git a/theodolite-quarkus/config/example-operator-benchmark.yaml b/theodolite-quarkus/config/example-operator-benchmark.yaml
index 3ed5218d8a8988b130e8d549c120cbca7329ffe3..8f9af3e955fe18de26326b0094578a71517a5aef 100644
--- a/theodolite-quarkus/config/example-operator-benchmark.yaml
+++ b/theodolite-quarkus/config/example-operator-benchmark.yaml
@@ -1,35 +1,38 @@
-apiVersion: theodolite.com/v1alpha1
+apiVersion: theodolite.com/v1
 kind: benchmark
 metadata:
   name: uc1-kstreams
-#name: "uc1-kstreams"
-appResource:
-  - "uc1-kstreams-deployment.yaml"
-  - "aggregation-service.yaml"
-  - "jmx-configmap.yaml"
-  - "uc1-service-monitor.yaml"
-loadGenResource:
-  - "uc1-load-generator-deployment.yaml"
-  - "uc1-load-generator-service.yaml"
-resourceTypes:
-  - typeName: "Instances"
-    patchers:
-      - type: "ReplicaPatcher"
-        resource: "uc1-kstreams-deployment.yaml"
-loadTypes:
-  - typeName: "NumSensors"
-    patchers:
-      - type: "EnvVarPatcher"
-        resource: "uc1-load-generator-deployment.yaml"
-        container: "workload-generator"
-        variableName: "NUM_SENSORS"
-      - type: "NumSensorsLoadGeneratorReplicaPatcher"
-        resource: "uc1-load-generator-deployment.yaml"
-kafkaConfig:
-  bootstrapServer: "theodolite-cp-kafka:9092"
-  topics:
-    - name: "input"
-      numPartitions: 40
-      replicationFactor: 1
-    - name: "theodolite-.*"
-      removeOnly: True
\ No newline at end of file
+spec:
+  appResource:
+    - "uc1-kstreams-deployment.yaml"
+    - "aggregation-service.yaml"
+    - "jmx-configmap.yaml"
+    - "uc1-service-monitor.yaml"
+  loadGenResource:
+    - "uc1-load-generator-deployment.yaml"
+    - "uc1-load-generator-service.yaml"
+  resourceTypes:
+    - typeName: "Instances"
+      patchers:
+        - type: "ReplicaPatcher"
+          resource: "uc1-kstreams-deployment.yaml"
+  loadTypes:
+      - typeName: "NumSensors"
+        patchers:
+          - type: "EnvVarPatcher"
+            resource: "uc1-load-generator-deployment.yaml"
+            properties:
+               variableName: "NUM_SENSORS"
+               container: "workload-generator"
+          - type: "NumSensorsLoadGeneratorReplicaPatcher"
+            resource: "uc1-load-generator-deployment.yaml"
+            properties:
+              loadGenMaxRecords: "15000"
+  kafkaConfig:
+    bootstrapServer: "theodolite-cp-kafka:9092"
+    topics:
+      - name: "input"
+        numPartitions: 40
+        replicationFactor: 1
+      - name: "theodolite-.*"
+        removeOnly: True
\ No newline at end of file
diff --git a/theodolite-quarkus/config/example-operator-execution.yaml b/theodolite-quarkus/config/example-operator-execution.yaml
index 882c38a97c882ac180a2416e0b5046fa6d467efd..9b2a1facbd8be3411407dfcf3cad39fd9f3de6b6 100644
--- a/theodolite-quarkus/config/example-operator-execution.yaml
+++ b/theodolite-quarkus/config/example-operator-execution.yaml
@@ -1,53 +1,57 @@
-apiVersion: theodolite.com/v1alpha1
+apiVersion: theodolite.com/v1
 kind: execution
 metadata:
   name: example-execution
-#name: example-execution
-benchmark: "uc1-kstreams"
-load:
-  loadType: "NumSensors"
-  loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
-resources:
-  resourceType: "Instances"
-  resourceValues: [1, 2, 3, 4, 5]
-slos:
-  - sloType: "lag trend"
-    threshold: 2000
-    prometheusUrl: "http://prometheus-operated:9090"
-    externalSloUrl: "http://localhost:80/evaluate-slope"
-    offset: 0
-    warmup: 60 # in seconds
-execution:
-  strategy: "LinearSearch"
-  duration: 300 # in seconds
-  repetitions: 1
-  delay: 30 # in seconds
-  restrictions:
-    - "LowerBound"
-configOverrides: []
-#  - patcher:
-#      type: "NodeSelectorPatcher"
-#      resource: "uc1-load-generator-deployment.yaml"
-#      variableName: "env"
-#    value: "prod"
-#  - patcher:
-#      type: "NodeSelectorPatcher"
-#      resource: "uc1-kstreams-deployment.yaml"
-#      variableName: "env"
-#    value: "prod"
-#  - patcher:
-#      type: "ResourceLimitPatcher"
-#      resource: "uc1-kstreams-deployment.yaml"
-#      container: "uc-application"
-#      variableName: "cpu"
-#    value: "1000m"
-#  - patcher:
-#      type: "ResourceLimitPatcher"
-#      resource: "uc1-kstreams-deployment.yaml"
-#      container: "uc-application"
-#      variableName: "memory"
-#    value: "2Gi"
-#  - patcher:
-#      type: "SchedulerNamePatcher"
-#      resource: "uc1-kstreams-deployment.yaml"
-#    value: "random-scheduler"
+spec:
+  benchmark: "uc1-kstreams"
+  load:
+    loadType: "NumSensors"
+    loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
+  resources:
+    resourceType: "Instances"
+    resourceValues: [1, 2, 3, 4, 5]
+  slos:
+    - sloType: "lag trend"
+      threshold: 2000
+      prometheusUrl: "http://prometheus-operated:9090"
+      externalSloUrl: "http://localhost:80/evaluate-slope"
+      offset: 0
+      warmup: 60 # in seconds
+  execution:
+    strategy: "LinearSearch"
+    duration: 300 # in seconds
+    repetitions: 1
+    loadGenerationDelay: 30 # in seconds
+    restrictions:
+      - "LowerBound"
+  configOverrides:
+    # - patcher:
+    #     type: "NodeSelectorPatcher"
+    #     resource: "uc1-load-generator-deployment.yaml"
+    #     properties:
+    #       variableName: "env"
+    #     value: "prod"
+    # - patcher:
+    #     type: "NodeSelectorPatcher"
+    #     resource: "uc1-kstreams-deployment.yaml"
+    #     properties:
+    #       variableName: "env"
+    #   value: "prod"
+    # - patcher:
+    #     type: "ResourceLimitPatcher"
+    #     resource: "uc1-kstreams-deployment.yaml"
+    #     properties:
+    #       container: "uc-application"
+    #       limitedResource: "cpu"
+    #   value: "1000m"
+    # - patcher:
+    #     type: "ResourceLimitPatcher"
+    #     resource: "uc1-kstreams-deployment.yaml"
+    #     properties:
+    #       container: "uc-application"
+    #       limitedResource: "memory"
+    #   value: "2Gi"
+    #  - patcher:
+    #      type: "SchedulerNamePatcher"
+    #      resource: "uc1-kstreams-deployment.yaml"
+    #    value: "random-scheduler"
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt
index 95af36d1b14eb4d664ffd0d3d463df17fd8fb534..d57a28e8bbcf4dc101e4814ecaa0d52fe28c08a9 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/Benchmark.kt
@@ -1,5 +1,8 @@
 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
@@ -22,6 +25,7 @@ interface Benchmark {
         load: LoadDimension,
         res: Resource,
         configurationOverrides: List<ConfigurationOverride?>,
-        delay: Long
+        loadGenerationDelay: Long,
+        afterTeardownDelay: Long
     ): BenchmarkDeployment
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
index 40ab663e179735be61356947df7c37e9edd0a2ea..62ab75898d16ff2732ab6aa5c254ec8f87fb7266 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
@@ -2,8 +2,6 @@ package theodolite.benchmark
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize
 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 kotlin.properties.Delegates
@@ -26,7 +24,7 @@ import kotlin.properties.Delegates
  */
 @JsonDeserialize
 @RegisterForReflection
-class BenchmarkExecution : CustomResource(), Namespaced {
+class BenchmarkExecution : KubernetesResource {
     var executionId: Int = 0
     lateinit var name: String
     lateinit var benchmark: String
@@ -34,7 +32,7 @@ class BenchmarkExecution : CustomResource(), Namespaced {
     lateinit var resources: ResourceDefinition
     lateinit var slos: List<Slo>
     lateinit var execution: Execution
-    lateinit var configOverrides: List<ConfigurationOverride?>
+    lateinit var configOverrides: MutableList<ConfigurationOverride?>
 
     /**
      * This execution encapsulates the [strategy], the [duration], the [repetitions], and the [restrictions]
@@ -48,6 +46,7 @@ class BenchmarkExecution : CustomResource(), Namespaced {
         var repetitions by Delegates.notNull<Int>()
         lateinit var restrictions: List<String>
         var loadGenerationDelay = 0L
+        var afterTeardownDelay = 5L
     }
 
     /**
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecutionList.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecutionList.kt
deleted file mode 100644
index 50e8967f20aebad880ebd218136749af8e3ea6ee..0000000000000000000000000000000000000000
--- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/BenchmarkExecutionList.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package theodolite.benchmark
-
-import io.fabric8.kubernetes.client.CustomResourceList
-
-class BenchmarkExecutionList : CustomResourceList<BenchmarkExecution>()
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
index b5316a3df78e7291569ec1d36e561a5445b6f86d..aa9c36ad912437e3b104dccf6ff1f4dea5905946 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
@@ -1,5 +1,6 @@
 package theodolite.benchmark
 
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
 import io.fabric8.kubernetes.api.model.KubernetesResource
 import io.fabric8.kubernetes.api.model.Namespaced
 import io.fabric8.kubernetes.client.CustomResource
@@ -30,16 +31,18 @@ private var DEFAULT_NAMESPACE = "default"
  *  for the deserializing in the [theodolite.execution.operator.TheodoliteOperator].
  * @constructor construct an empty Benchmark.
  */
+@JsonDeserialize
 @RegisterForReflection
-class KubernetesBenchmark : Benchmark, CustomResource(), Namespaced {
+class KubernetesBenchmark: KubernetesResource, Benchmark{
     lateinit var name: String
     lateinit var appResource: List<String>
     lateinit var loadGenResource: List<String>
     lateinit var resourceTypes: List<TypeName>
     lateinit var loadTypes: List<TypeName>
     lateinit var kafkaConfig: KafkaConfig
-    private val namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
-    var path = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
+    var namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
+    var path =  System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
+
 
     /**
      * Loads [KubernetesResource]s.
@@ -71,7 +74,8 @@ class KubernetesBenchmark : Benchmark, CustomResource(), Namespaced {
         load: LoadDimension,
         res: Resource,
         configurationOverrides: List<ConfigurationOverride?>,
-        loadGenerationDelay: Long
+        loadGenerationDelay: Long,
+        afterTeardownDelay: Long
     ): BenchmarkDeployment {
         logger.info { "Using $namespace as namespace." }
         logger.info { "Using $path as resource path." }
@@ -100,6 +104,7 @@ class KubernetesBenchmark : Benchmark, CustomResource(), Namespaced {
             appResources = appResources.map { it.second },
             loadGenResources = loadGenResources.map { it.second },
             loadGenerationDelay = loadGenerationDelay,
+            afterTeardownDelay = afterTeardownDelay,
             kafkaConfig = hashMapOf("bootstrap.servers" to kafkaConfig.bootstrapServer),
             topics = kafkaConfig.topics,
             client = DefaultKubernetesClient().inNamespace(namespace)
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
index 7d1c3f4ba727b8c149e3c5678ad406fa293c8f5b..6cf239676ddb24752f4754a85fc62657f9eb6603 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
@@ -26,6 +26,7 @@ class KubernetesBenchmarkDeployment(
     val appResources: List<KubernetesResource>,
     val loadGenResources: List<KubernetesResource>,
     private val loadGenerationDelay: Long,
+    private val afterTeardownDelay: Long,
     private val kafkaConfig: HashMap<String, Any>,
     private val topics: List<KafkaConfig.TopicWrapper>,
     private val client: NamespacedKubernetesClient
@@ -33,7 +34,6 @@ class KubernetesBenchmarkDeployment(
     private val kafkaController = TopicManager(this.kafkaConfig)
     private val kubernetesManager = K8sManager(client)
     private val LAG_EXPORTER_POD_LABEL = "app.kubernetes.io/name=kafka-lag-exporter"
-    private val SLEEP_AFTER_TEARDOWN = 5000L
 
     /**
      * Setup a [KubernetesBenchmark] using the [TopicManager] and the [K8sManager]:
@@ -61,7 +61,7 @@ class KubernetesBenchmarkDeployment(
         appResources.forEach { kubernetesManager.remove(it) }
         kafkaController.removeTopics(this.topics.map { topic -> topic.name })
         KafkaLagExporterRemover(client).remove(LAG_EXPORTER_POD_LABEL)
-        logger.info { "Teardown complete. Wait $SLEEP_AFTER_TEARDOWN ms to let everything come down." }
-        Thread.sleep(SLEEP_AFTER_TEARDOWN)
+        logger.info { "Teardown complete. Wait $afterTeardownDelay ms to let everything come down." }
+        Thread.sleep(Duration.ofSeconds(afterTeardownDelay).toMillis())
     }
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkList.kt b/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkList.kt
deleted file mode 100644
index 0930875e96146fda58301478bda68b00c229e99f..0000000000000000000000000000000000000000
--- a/theodolite-quarkus/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkList.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package theodolite.benchmark
-
-import io.fabric8.kubernetes.client.CustomResourceList
-
-class KubernetesBenchmarkList : CustomResourceList<KubernetesBenchmark>()
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
index c5d691eb8f1437726bcce22500ad995bc1b6e4da..ef4d371173c7099eb091f90cddbe26d31e6522be 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
@@ -2,6 +2,7 @@ package theodolite.evaluation
 
 import mu.KotlinLogging
 import theodolite.benchmark.BenchmarkExecution
+import theodolite.util.IOHandler
 import theodolite.util.LoadDimension
 import theodolite.util.Resource
 import java.text.Normalizer
@@ -34,25 +35,28 @@ class AnalysisExecutor(
      *  @param executionDuration of the experiment.
      *  @return true if the experiment succeeded.
      */
-    fun analyze(load: LoadDimension, res: Resource, executionDuration: Duration): Boolean {
+    fun analyze(load: LoadDimension, res: Resource, executionIntervals: List<Pair<Instant, Instant>>): Boolean {
         var result = false
+        var repetitionCounter = 1
 
         try {
-            val prometheusData = fetcher.fetchMetric(
-                start = Instant.now().minus(executionDuration),
-                end = Instant.now(),
-                query = "sum by(group)(kafka_consumergroup_group_lag >= 0)"
-            )
+            val ioHandler = IOHandler()
+            val resultsFolder: String = ioHandler.getResultFolderURL()
+            val fileURL = "${resultsFolder}exp${executionId}_${load.get()}_${res.get()}_${slo.sloType.toSlug()}"
+
+            val prometheusData = executionIntervals
+                .map { interval -> fetcher.fetchMetric(
+                        start = interval.first,
+                        end = interval.second,
+                        query = "sum by(group)(kafka_consumergroup_group_lag >= 0)") }
 
-            var resultsFolder: String = System.getenv("RESULTS_FOLDER")
-            if (resultsFolder.isNotEmpty()){
-                resultsFolder += "/"
+            prometheusData.forEach{ data ->
+                ioHandler.writeToCSVFile(
+                    fileURL = "${fileURL}_${repetitionCounter++}",
+                    data = data.getResultAsList(),
+                    columns = listOf("group", "timestamp", "value"))
             }
 
-            CsvExporter().toCsv(
-                name = "${resultsFolder}exp${executionId}_${load.get()}_${res.get()}_${slo.sloType.toSlug()}",
-                prom = prometheusData
-            )
             val sloChecker = SloCheckerFactory().create(
                 sloType = slo.sloType,
                 externalSlopeURL = slo.externalSloUrl,
@@ -60,10 +64,7 @@ class AnalysisExecutor(
                 warmup = slo.warmup
             )
 
-            result = sloChecker.evaluate(
-                start = Instant.now().minus(executionDuration),
-                end = Instant.now(), fetchedData = prometheusData
-            )
+            result = sloChecker.evaluate(prometheusData)
 
         } catch (e: Exception) {
             logger.error { "Evaluation failed for resource '${res.get()}' and load '${load.get()}'. Error: $e" }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/CsvExporter.kt b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/CsvExporter.kt
deleted file mode 100644
index 970d1487014bfbddf7391e381d27ad5dbb246a7d..0000000000000000000000000000000000000000
--- a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/CsvExporter.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package theodolite.evaluation
-
-import mu.KotlinLogging
-import theodolite.util.PrometheusResponse
-import java.io.File
-import java.io.PrintWriter
-import java.util.*
-
-private val logger = KotlinLogging.logger {}
-
-/**
- *  Used to document the data received from prometheus for additional offline analysis.
- */
-class CsvExporter {
-
-    /**
-     * Uses the [PrintWriter] to transform a [PrometheusResponse] to a CSV file.
-     * @param name of the file.
-     * @param prom Response that is documented.
-     *
-     */
-    fun toCsv(name: String, prom: PrometheusResponse) {
-        val responseArray = promResponseToList(prom)
-        val csvOutputFile = File("$name.csv")
-
-        PrintWriter(csvOutputFile).use { pw ->
-            pw.println(listOf("group", "timestamp", "value").joinToString(separator=","))
-            responseArray.forEach {
-                pw.println(it.joinToString(separator=","))
-            }
-        }
-        logger.info { "Wrote CSV file: $name to ${csvOutputFile.absolutePath}." }
-    }
-
-    /**
-     * Converts a [PrometheusResponse] into a [List] of [List]s of [String]s
-     */
-    private fun promResponseToList(prom: PrometheusResponse): List<List<String>> {
-        val name = prom.data?.result?.get(0)?.metric?.group.toString()
-        val values = prom.data?.result?.get(0)?.values
-        val dataList = mutableListOf<List<String>>()
-
-        if (values != null) {
-            for (maybeValuePair in values) {
-                val valuePair = maybeValuePair as List<*>
-                val timestamp = (valuePair[0] as Double).toLong().toString()
-                val value = valuePair[1].toString()
-                dataList.add(listOf(name, timestamp, value))
-            }
-        }
-        return Collections.unmodifiableList(dataList)
-    }
-}
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt
index 8eac05a815e0bc45e1abc38bcdf0352e61bd7730..f7ebee8faf740583dbe6a37381a599e9bde19280 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt
@@ -35,10 +35,10 @@ class ExternalSloChecker(
      * @return true if the experiment was successful(the threshold was not exceeded.
      * @throws ConnectException if the external service could not be reached.
      */
-    override fun evaluate(start: Instant, end: Instant, fetchedData: PrometheusResponse): Boolean {
+    override fun evaluate(fetchedData: List<PrometheusResponse>): Boolean {
         var counter = 0
         val data = Gson().toJson(mapOf(
-            "total_lag" to fetchedData.data?.result,
+            "total_lags" to fetchedData.map { it.data?.result},
             "threshold" to threshold,
             "warmup" to warmup))
 
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt
index 758dcdefcaee79654d8ff65f0f798832aafc1294..9ee5fe7ef34ce5b6214882ce2c1d19677f1d7130 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/evaluation/SloChecker.kt
@@ -1,14 +1,12 @@
 package theodolite.evaluation
 
 import theodolite.util.PrometheusResponse
-import java.time.Instant
 
 /**
  * A SloChecker can be used to evaluate data from Prometheus.
  * @constructor Creates an empty SloChecker
  */
 interface SloChecker {
-
     /**
      * Evaluates [fetchedData] and returns if the experiment was successful.
      * Returns if the evaluated experiment was successful.
@@ -18,5 +16,5 @@ interface SloChecker {
      * @param fetchedData from Prometheus that will be evaluated.
      * @return true if experiment was successful. Otherwise false.
      */
-    fun evaluate(start: Instant, end: Instant, fetchedData: PrometheusResponse): Boolean
+    fun evaluate(fetchedData: List<PrometheusResponse>): Boolean
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt
index 909ae77a95dfef7dfc1dafd7bd0a326a72ef1424..e7b511d8c83b5abccece1204aad2a4a9ecfdfd26 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt
@@ -26,8 +26,10 @@ abstract class BenchmarkExecutor(
     val executionDuration: Duration,
     val configurationOverrides: List<ConfigurationOverride?>,
     val slo: BenchmarkExecution.Slo,
+    val repetitions: Int,
     val executionId: Int,
-    val loadGenerationDelay: Long
+    val loadGenerationDelay: Long,
+    val afterTeardownDelay: Long
 ) {
 
     var run: AtomicBoolean = AtomicBoolean(true)
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
index 22db5076bee51e03318aa9ac95e66c2d61d27f28..3afc85f0a8cb67011763498a662b447ce2c07f0f 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
@@ -5,11 +5,9 @@ import mu.KotlinLogging
 import theodolite.benchmark.Benchmark
 import theodolite.benchmark.BenchmarkExecution
 import theodolite.evaluation.AnalysisExecutor
-import theodolite.util.ConfigurationOverride
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
-import theodolite.util.Results
+import theodolite.util.*
 import java.time.Duration
+import java.time.Instant
 
 private val logger = KotlinLogging.logger {}
 
@@ -20,41 +18,56 @@ class BenchmarkExecutorImpl(
     executionDuration: Duration,
     configurationOverrides: List<ConfigurationOverride?>,
     slo: BenchmarkExecution.Slo,
+    repetitions: Int,
     executionId: Int,
-    loadGenerationDelay: Long
-) : BenchmarkExecutor(benchmark, results, executionDuration, configurationOverrides, slo, executionId, loadGenerationDelay) {
+    loadGenerationDelay: Long,
+    afterTeardownDelay: Long
+) : BenchmarkExecutor(benchmark, results, executionDuration, configurationOverrides, slo, repetitions, executionId, loadGenerationDelay, afterTeardownDelay) {
     override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
         var result = false
-        val benchmarkDeployment = benchmark.buildDeployment(load, res, configurationOverrides, loadGenerationDelay)
+        val executionIntervals: MutableList<Pair<Instant, Instant>> = ArrayList()
 
-        try {
-            benchmarkDeployment.setup()
-            this.waitAndLog()
-        } catch (e: Exception) {
-            logger.error { "Error while setting up experiment with id ${this.executionId}." }
-            logger.error { "Error is: $e" }
-            this.run.set(false)
+        for (i in 1.rangeTo(repetitions)) {
+            logger.info { "Run repetition $i/$repetitions" }
+            if (this.run.get()) {
+                executionIntervals.add(runSingleExperiment(load,res))
+            } else {
+                break
+            }
         }
 
         /**
          * 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,
-                executionDuration = executionDuration
-            )
+            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 from = Instant.now()
+        try {
+            benchmarkDeployment.setup()
+            this.waitAndLog()
+        } catch (e: Exception) {
+            logger.error { "Error while setup experiment." }
+            logger.error { "Error is: $e" }
+            this.run.set(false)
+        }
+        val to = Instant.now()
         try {
             benchmarkDeployment.teardown()
         } catch (e: Exception) {
             logger.warn { "Error while tearing down the benchmark deployment." }
             logger.debug { "Teardown failed, caused by: $e" }
         }
-
-        return result
+        return Pair(from,to)
     }
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt
index 80e1ac2341d9f8608d70b39a0d99f7b88dd7f108..0ff8379a0af4b11154214dde021d7c60609631d1 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/Shutdown.kt
@@ -31,7 +31,8 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b
                 load = LoadDimension(0, emptyList()),
                 res = Resource(0, emptyList()),
                 configurationOverrides = benchmarkExecution.configOverrides,
-                loadGenerationDelay = 0L
+                loadGenerationDelay = 0L,
+                afterTeardownDelay = 5L
             )
             deployment.teardown()
         } catch (e: Exception) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
index c297251e30c17e5824c2541365164d9824718073..c73aaae08489c25a40163d4edb1607247fae010a 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
@@ -1,22 +1,13 @@
 package theodolite.execution
 
-import com.google.gson.GsonBuilder
 import mu.KotlinLogging
 import theodolite.benchmark.BenchmarkExecution
 import theodolite.benchmark.KubernetesBenchmark
 import theodolite.patcher.PatcherDefinitionFactory
 import theodolite.strategies.StrategyFactory
 import theodolite.strategies.searchstrategy.CompositeStrategy
-import theodolite.util.Config
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
-import theodolite.util.Results
+import theodolite.util.*
 import java.io.File
-import java.io.PrintWriter
-import java.lang.IllegalArgumentException
-import java.lang.Thread.sleep
-import java.nio.file.Files
-import java.nio.file.Path
 import java.time.Duration
 
 
@@ -71,10 +62,24 @@ class TheodoliteExecutor(
                 executionDuration = executionDuration,
                 configurationOverrides = config.configOverrides,
                 slo = config.slos[0],
+                repetitions = config.execution.repetitions,
                 executionId = config.executionId,
-                loadGenerationDelay = config.execution.loadGenerationDelay
+                loadGenerationDelay = config.execution.loadGenerationDelay,
+                afterTeardownDelay = config.execution.afterTeardownDelay
             )
 
+        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}" }
+        }
+
+        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}" }
+        }
+
         return Config(
             loads = config.load.loadValues.map { load -> LoadDimension(load, loadDimensionPatcherDefinition) },
             resources = config.resources.resourceValues.map { resource ->
@@ -102,34 +107,16 @@ class TheodoliteExecutor(
         return this.kubernetesBenchmark
     }
 
-    private fun getResultFolderString(): String {
-        var resultsFolder: String = System.getenv("RESULTS_FOLDER") ?: ""
-        val createResultsFolder = System.getenv("CREATE_RESULTS_FOLDER") ?: "false"
-
-        if (resultsFolder != ""){
-            logger.info { "RESULT_FOLDER: $resultsFolder" }
-            val directory = File(resultsFolder)
-            if (!directory.exists()) {
-                logger.error { "Folder $resultsFolder does not exist" }
-                if (createResultsFolder.toBoolean()) {
-                    directory.mkdirs()
-                } else {
-                    throw IllegalArgumentException("Result folder not found")
-                }
-            }
-            resultsFolder += "/"
-        }
-        return  resultsFolder
-    }
-
     /**
      * Run all experiments which are specified in the corresponding
      * execution and benchmark objects.
      */
     fun run() {
-        val resultsFolder = getResultFolderString()
-        storeAsFile(this.config, "$resultsFolder${this.config.executionId}-execution-configuration")
-        storeAsFile(kubernetesBenchmark, "$resultsFolder${this.config.executionId}-benchmark-configuration")
+        val ioHandler = IOHandler()
+        val resultsFolder = ioHandler.getResultFolderURL()
+        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")
 
         val config = buildConfig()
         // execute benchmarks for each load
@@ -138,14 +125,17 @@ class TheodoliteExecutor(
                 config.compositeStrategy.findSuitableResource(load, config.resources)
             }
         }
-        storeAsFile(config.compositeStrategy.benchmarkExecutor.results, "$resultsFolder${this.config.executionId}-result")
+        ioHandler.writeToJSONFile(config.compositeStrategy.benchmarkExecutor.results, "$resultsFolder${this.config.executionId}-result")
     }
 
-    private fun <T> storeAsFile(saveObject: T, filename: String) {
-        val gson = GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create()
-
-        PrintWriter(filename).use { pw ->
-            pw.println(gson.toJson(saveObject))
-        }
+   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-quarkus/src/main/kotlin/theodolite/execution/TheodoliteYamlExecutor.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteYamlExecutor.kt
index 8b2909f7658f4dffcfd961cad8cd00eb013a160c..b9977029703c8012ada7fb3d7766bfa321a836c3 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteYamlExecutor.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/TheodoliteYamlExecutor.kt
@@ -31,8 +31,8 @@ class TheodoliteYamlExecutor {
     fun start() {
         logger.info { "Theodolite started" }
 
-        val executionPath = System.getenv("THEODOLITE_EXECUTION") ?: "./config/BenchmarkExecution.yaml"
-        val benchmarkPath = System.getenv("THEODOLITE_BENCHMARK") ?: "./config/BenchmarkType.yaml"
+        val executionPath = System.getenv("THEODOLITE_EXECUTION") ?: "./config/example-execution-yaml-resource.yaml"
+        val benchmarkPath = System.getenv("THEODOLITE_BENCHMARK") ?: "./config/example-benchmark-yaml-resource.yaml"
 
         logger.info { "Using $executionPath for BenchmarkExecution" }
         logger.info { "Using $benchmarkPath for BenchmarkType" }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..75cbcad051e2055f25d876e66e0fffcdc249c4f5
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt
@@ -0,0 +1,55 @@
+package theodolite.execution.operator
+
+import io.fabric8.kubernetes.api.model.Namespaced
+import io.fabric8.kubernetes.client.CustomResource
+import io.fabric8.kubernetes.client.CustomResourceDoneable
+import io.fabric8.kubernetes.client.CustomResourceList
+import io.fabric8.kubernetes.client.KubernetesClient
+import io.fabric8.kubernetes.client.dsl.MixedOperation
+import io.fabric8.kubernetes.client.dsl.Resource
+import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
+import java.lang.Thread.sleep
+
+abstract class AbstractStateHandler<T,L,D>(
+    private val context: CustomResourceDefinitionContext,
+    private val client: KubernetesClient,
+    private val crd: Class<T>,
+    private val crdList: Class<L>,
+    private val donableCRD: Class<D>
+    ): StateHandler where T : CustomResource, T: Namespaced, L: CustomResourceList<T>, D: CustomResourceDoneable<T> {
+
+    private val crdClient: MixedOperation<T, L, D, Resource<T, D>> =
+        this.client.customResources(this.context, this.crd, this.crdList, this.donableCRD)
+
+    @Synchronized
+    override fun setState(resourceName: String, f: (CustomResource) -> CustomResource?) {
+        this.crdClient
+            .inNamespace(this.client.namespace)
+            .list().items
+            .filter { item -> item.metadata.name == resourceName }
+            .map { customResource -> f(customResource) }
+            .forEach { this.crdClient.updateStatus(it as T) }
+       }
+
+    @Synchronized
+    override fun getState(resourceName: String, f: (CustomResource) -> String?): String? {
+        return this.crdClient
+            .inNamespace(this.client.namespace)
+            .list().items
+            .filter { item -> item.metadata.name == resourceName }
+            .map { customResource -> f(customResource) }
+            .firstOrNull()
+    }
+
+    @Synchronized
+    override fun blockUntilStateIsSet(resourceName: String, desiredStatusString: String, f: (CustomResource) -> String?, maxTries: Int): Boolean {
+        for (i in 0.rangeTo(maxTries)) {
+            val currentStatus = getState(resourceName, f)
+                if(currentStatus == desiredStatusString) {
+                    return true
+                }
+            sleep(50)
+        }
+        return false
+    }
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/BenchmarkEventHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/BenchmarkEventHandler.kt
deleted file mode 100644
index 7c8188e3c342cfc1b22fefdd3ca91e7dbce85905..0000000000000000000000000000000000000000
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/BenchmarkEventHandler.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package theodolite.execution.operator
-
-import io.fabric8.kubernetes.client.informers.ResourceEventHandler
-import mu.KotlinLogging
-import theodolite.benchmark.KubernetesBenchmark
-
-private val logger = KotlinLogging.logger {}
-
-/**
- * Handles adding, updating and deleting KubernetesBenchmarks.
- *
- * @param controller The TheodoliteController that handles the application state
- *
- * @see TheodoliteController
- * @see KubernetesBenchmark
- */
-class BenchmarkEventHandler(private val controller: TheodoliteController) : ResourceEventHandler<KubernetesBenchmark> {
-
-    /**
-     * Add a KubernetesBenchmark.
-     *
-     * @param benchmark the KubernetesBenchmark to add
-     *
-     * @see KubernetesBenchmark
-     */
-    override fun onAdd(benchmark: KubernetesBenchmark) {
-        benchmark.name = benchmark.metadata.name
-        logger.info { "Add new benchmark ${benchmark.name}." }
-        this.controller.benchmarks[benchmark.name] = benchmark
-    }
-
-    /**
-     * Update a KubernetesBenchmark.
-     *
-     * @param oldBenchmark the KubernetesBenchmark to update
-     * @param newBenchmark the updated KubernetesBenchmark
-     *
-     * @see KubernetesBenchmark
-     */
-    override fun onUpdate(oldBenchmark: KubernetesBenchmark, newBenchmark: KubernetesBenchmark) {
-        logger.info { "Update benchmark ${newBenchmark.metadata.name}." }
-        newBenchmark.name = newBenchmark.metadata.name
-        if (this.controller.isInitialized() && this.controller.executor.getBenchmark().name == oldBenchmark.metadata.name) {
-            this.controller.isUpdated.set(true)
-            this.controller.executor.executor.run.compareAndSet(true, false)
-        } else {
-            onAdd(newBenchmark)
-        }
-    }
-
-    /**
-     * Delete a KubernetesBenchmark.
-     *
-     * @param benchmark the KubernetesBenchmark to delete
-     *
-     * @see KubernetesBenchmark
-     */
-    override fun onDelete(benchmark: KubernetesBenchmark, b: Boolean) {
-        logger.info { "Delete benchmark ${benchmark.metadata.name}." }
-        this.controller.benchmarks.remove(benchmark.metadata.name)
-        if (this.controller.isInitialized() && this.controller.executor.getBenchmark().name == benchmark.metadata.name) {
-            this.controller.isUpdated.set(true)
-            this.controller.executor.executor.run.compareAndSet(true, false)
-            logger.info { "Current benchmark stopped." }
-        }
-    }
-}
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6c8c48f791543b6d8a7716cf26a80bdb449ee7a7
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt
@@ -0,0 +1,76 @@
+package theodolite.execution.operator
+
+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.model.crd.*
+
+private val logger = KotlinLogging.logger {}
+
+class ClusterSetup(
+    private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, DoneableExecution, Resource<ExecutionCRD, DoneableExecution>>,
+    private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, DoneableBenchmark, Resource<BenchmarkCRD, DoneableBenchmark>>,
+    private val client: NamespacedKubernetesClient
+
+    ) {
+    private val serviceMonitorContext = K8sContextFactory().create(
+        api = "v1",
+        scope = "Namespaced",
+        group = "monitoring.coreos.com",
+        plural = "servicemonitors"
+    )
+
+    fun clearClusterState(){
+        stopRunningExecution()
+        clearByLabel()
+    }
+
+    private fun stopRunningExecution() {
+        executionCRDClient
+            .inNamespace(client.namespace)
+            .list()
+            .items
+            .asSequence()
+            .filter {   it.status.executionState == States.RUNNING.value }
+            .forEach { execution ->
+                val benchmark = benchmarkCRDClient
+                    .inNamespace(client.namespace)
+                    .list()
+                    .items
+                    .firstOrNull { it.metadata.name == execution.spec.benchmark }
+
+                if (benchmark != null) {
+                    execution.spec.name = execution.metadata.name
+                    benchmark.spec.name = benchmark.metadata.name
+                    Shutdown(execution.spec, benchmark.spec).start()
+                } else {
+                    logger.error {
+                        "Execution with state ${States.RUNNING.value} was found, but no corresponding benchmark. " +
+                                "Could not initialize cluster." }
+                }
+
+
+            }
+        }
+
+    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")))
+        )
+            .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-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt
index ea62b7b895fce772a1f89019ea4aaac0f3957dc1..a1617b4988d500baab7b02bf5fa993f7a4ae76a3 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt
@@ -1,8 +1,11 @@
 package theodolite.execution.operator
 
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
 import io.fabric8.kubernetes.client.informers.ResourceEventHandler
 import mu.KotlinLogging
 import theodolite.benchmark.BenchmarkExecution
+import theodolite.model.crd.*
 
 private val logger = KotlinLogging.logger {}
 
@@ -14,17 +17,30 @@ private val logger = KotlinLogging.logger {}
  * @see TheodoliteController
  * @see BenchmarkExecution
  */
-class ExecutionHandler(private val controller: TheodoliteController) : ResourceEventHandler<BenchmarkExecution> {
+class ExecutionHandler(
+    private val controller: TheodoliteController,
+    private val stateHandler: ExecutionStateHandler
+) : ResourceEventHandler<ExecutionCRD> {
+    private val gson: Gson = GsonBuilder().enableComplexMapKeySerialization().create()
 
     /**
      * Add an execution to the end of the queue of the TheodoliteController.
      *
-     * @param execution the execution to add
+     * @param ExecutionCRD the execution to add
      */
-    override fun onAdd(execution: BenchmarkExecution) {
-        execution.name = execution.metadata.name
-        logger.info { "Add new execution ${execution.metadata.name} to queue." }
-        this.controller.executionsQueue.add(execution)
+    @Synchronized
+    override fun onAdd(execution: ExecutionCRD) {
+        logger.info { "Add execution ${execution.metadata.name}" }
+        execution.spec.name = execution.metadata.name
+        when (this.stateHandler.getExecutionState(execution.metadata.name)) {
+            null -> 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)
+                    }
+                }
+        }
     }
 
     /**
@@ -32,40 +48,39 @@ class ExecutionHandler(private val controller: TheodoliteController) : ResourceE
      * added to the beginning of the queue of the TheodoliteController.
      * Otherwise, it is just added to the beginning of the queue.
      *
-     * @param oldExecution the old execution
-     * @param newExecution the new execution
+     * @param oldExecutionCRD the old execution
+     * @param newExecutionCRD the new execution
      */
-    override fun onUpdate(oldExecution: BenchmarkExecution, newExecution: BenchmarkExecution) {
-        logger.info { "Add updated execution to queue." }
-        newExecution.name = newExecution.metadata.name
-        try {
-            this.controller.executionsQueue.removeIf { e -> e.name == newExecution.metadata.name }
-        } catch (e: NullPointerException) {
-            logger.warn { "No execution found for deletion" }
-        }
-        this.controller.executionsQueue.addFirst(newExecution)
-        if (this.controller.isInitialized() && this.controller.executor.getExecution().name == newExecution.metadata.name) {
-            this.controller.isUpdated.set(true)
-            this.controller.executor.executor.run.compareAndSet(true, false)
+    @Synchronized
+    override fun onUpdate(oldExecution: ExecutionCRD, newExecution: ExecutionCRD) {
+        logger.info { "Receive update event for execution ${oldExecution.metadata.name}" }
+        newExecution.spec.name = newExecution.metadata.name
+        oldExecution.spec.name = oldExecution.metadata.name
+        if(gson.toJson(oldExecution.spec) != gson.toJson(newExecution.spec)) {
+            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)
+                }
+            }
         }
-    }
 
     /**
      * Delete an execution from the queue of the TheodoliteController.
      *
-     * @param execution the execution to delete
+     * @param ExecutionCRD the execution to delete
      */
-    override fun onDelete(execution: BenchmarkExecution, b: Boolean) {
-        try {
-            this.controller.executionsQueue.removeIf { e -> e.name == execution.metadata.name }
-            logger.info { "Delete execution ${execution.metadata.name} from queue." }
-        } catch (e: NullPointerException) {
-            logger.warn { "No execution found for deletion" }
-        }
-        if (this.controller.isInitialized() && this.controller.executor.getExecution().name == execution.metadata.name) {
-            this.controller.isUpdated.set(true)
-            this.controller.executor.executor.run.compareAndSet(true, false)
-            logger.info { "Current benchmark stopped." }
+    @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)) {
+            this.controller.stop()
         }
     }
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fe1b95f95c74efe77913ea435dd1ac896805b065
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt
@@ -0,0 +1,82 @@
+package theodolite.execution.operator
+
+import io.fabric8.kubernetes.client.CustomResource
+import io.fabric8.kubernetes.client.KubernetesClient
+import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
+import theodolite.model.crd.BenchmarkExecutionList
+import theodolite.model.crd.ExecutionCRD
+import theodolite.model.crd.States
+import java.lang.Thread.sleep
+import java.time.Duration
+import java.time.Instant
+import java.util.concurrent.atomic.AtomicBoolean
+
+class ExecutionStateHandler(context: CustomResourceDefinitionContext, val client: KubernetesClient):
+    AbstractStateHandler<ExecutionCRD, BenchmarkExecutionList, DoneableExecution>(
+        context = context,
+        client = client,
+        crd = ExecutionCRD::class.java,
+        crdList = BenchmarkExecutionList::class.java,
+        donableCRD = DoneableExecution::class.java) {
+
+    private var runExecutionDurationTimer: AtomicBoolean = AtomicBoolean(false)
+
+    private fun getExecutionLambda() = { cr: CustomResource ->
+        var execState = ""
+        if (cr is ExecutionCRD) { execState = cr.status.executionState }
+        execState
+    }
+
+    private fun getDurationLambda() = { cr: CustomResource ->
+        var execState = ""
+        if (cr is ExecutionCRD) { execState = cr.status.executionState }
+        execState
+    }
+
+    fun setExecutionState(resourceName: String, status: States): Boolean {
+        setState(resourceName) {cr -> if(cr is ExecutionCRD) cr.status.executionState = status.value; cr}
+        return blockUntilStateIsSet(resourceName, status.value, getExecutionLambda())
+    }
+
+    fun getExecutionState(resourceName: String) : States? {
+        val status = this.getState(resourceName, getExecutionLambda())
+        return  States.values().firstOrNull { it.value == status }
+    }
+
+    fun setDurationState(resourceName: String, duration: Duration) {
+        setState(resourceName) { cr -> if (cr is ExecutionCRD) cr.status.executionDuration = durationToK8sString(duration); cr }
+        blockUntilStateIsSet(resourceName, durationToK8sString(duration), getDurationLambda())
+    }
+
+    fun getDurationState(resourceName: String): String? {
+        return this.getState(resourceName, getDurationLambda())
+    }
+
+    private fun durationToK8sString(duration: Duration): String {
+        val sec = duration.seconds
+        return when {
+            sec <= 120 -> "${sec}s" // max 120s
+            sec < 60 * 99 -> "${duration.toMinutes()}m" // max 99m
+            sec < 60 * 60 * 99 -> "${duration.toHours()}h"   // max 99h
+            else -> "${duration.toDays()}d + ${duration.minusDays(duration.toDays()).toHours()}h"
+        }
+    }
+
+    fun startDurationStateTimer(resourceName: String) {
+        this.runExecutionDurationTimer.set(true)
+        val startTime = Instant.now().toEpochMilli()
+        Thread {
+            while (this.runExecutionDurationTimer.get()) {
+                val duration = Duration.ofMillis(Instant.now().minusMillis(startTime).toEpochMilli())
+                setDurationState(resourceName, duration)
+                sleep(100 * 1)
+            }
+        }.start()
+    }
+
+    @Synchronized
+    fun stopDurationStateTimer() {
+        this.runExecutionDurationTimer.set(false)
+        sleep(100 * 2)
+    }
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/LeaderElector.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/LeaderElector.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9d093e4851e5c43d29a3fea3057ccf01be612e63
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/LeaderElector.kt
@@ -0,0 +1,43 @@
+package theodolite.execution.operator
+
+import io.fabric8.kubernetes.client.DefaultKubernetesClient
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
+import io.fabric8.kubernetes.client.extended.leaderelection.LeaderCallbacks
+import io.fabric8.kubernetes.client.extended.leaderelection.LeaderElectionConfigBuilder
+import io.fabric8.kubernetes.client.extended.leaderelection.resourcelock.LeaseLock
+import mu.KotlinLogging
+import java.time.Duration
+import java.util.*
+import kotlin.reflect.KFunction0
+
+private val logger = KotlinLogging.logger {}
+
+class LeaderElector(
+    val client:  NamespacedKubernetesClient,
+    val name: String
+    ) {
+
+    fun getLeadership(leader: KFunction0<Unit>) {
+        val lockIdentity: String = UUID.randomUUID().toString()
+            DefaultKubernetesClient().use { kc ->
+                kc.leaderElector()
+                .withConfig(
+                    LeaderElectionConfigBuilder()
+                        .withName("Theodolite")
+                        .withLeaseDuration(Duration.ofSeconds(15L))
+                        .withLock(LeaseLock(client.namespace, name, lockIdentity))
+                        .withRenewDeadline(Duration.ofSeconds(10L))
+                        .withRetryPeriod(Duration.ofSeconds(2L))
+                        .withLeaderCallbacks(LeaderCallbacks(
+                            { Thread{leader()}.start() },
+                            { logger.info { "STOPPED LEADERSHIP" } }
+                        ) { newLeader: String? ->
+                           logger.info { "New leader elected $newLeader" }
+                        })
+                        .build()
+                )
+                .build().run()
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/StateHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/StateHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0fbd97e5cca4a9be220eb0b0c89ea0af129a7860
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/StateHandler.kt
@@ -0,0 +1,15 @@
+package theodolite.execution.operator
+
+import io.fabric8.kubernetes.client.CustomResource
+private const val MAX_TRIES: Int = 5
+
+interface StateHandler {
+    fun setState(resourceName: String, f: (CustomResource) -> CustomResource?)
+    fun getState(resourceName: String, f: (CustomResource) -> String?): String?
+    fun blockUntilStateIsSet(
+        resourceName: String,
+        desiredStatusString: String,
+        f: (CustomResource) -> String?,
+        maxTries: Int = MAX_TRIES): Boolean
+
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
index 0e889e0393e17fd65f4d8f12c5b95a3dbed7f593..3053c364e2d6d9bc9797c190f0a87d861089b556 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt
@@ -1,122 +1,194 @@
 package theodolite.execution.operator
 
 import io.fabric8.kubernetes.client.NamespacedKubernetesClient
-import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
+import io.fabric8.kubernetes.client.dsl.MixedOperation
+import io.fabric8.kubernetes.client.dsl.Resource
 import mu.KotlinLogging
 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 java.lang.Thread.sleep
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.ConcurrentLinkedDeque
-import java.util.concurrent.atomic.AtomicBoolean
-import java.util.concurrent.atomic.AtomicInteger
 
 private val logger = KotlinLogging.logger {}
 
 /**
  * The controller implementation for Theodolite.
  *
- * Maintains a Dequeue, based on ConcurrentLinkedDequeue, of executions to be executed for a benchmark.
- *
- * @param client The NamespacedKubernetesClient
- * @param executionContext The CustomResourceDefinitionContext
- *
  * @see NamespacedKubernetesClient
  * @see CustomResourceDefinitionContext
  * @see BenchmarkExecution
  * @see KubernetesBenchmark
  * @see ConcurrentLinkedDeque
  */
+
 class TheodoliteController(
-    val client: NamespacedKubernetesClient,
-    val executionContext: CustomResourceDefinitionContext,
-    val path: String
+    private val namespace: String,
+    val path: String,
+    private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, DoneableExecution, Resource<ExecutionCRD, DoneableExecution>>,
+    private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, DoneableBenchmark, Resource<BenchmarkCRD, DoneableBenchmark>>,
+    private val executionStateHandler: ExecutionStateHandler
 ) {
     lateinit var executor: TheodoliteExecutor
-    val executionsQueue: ConcurrentLinkedDeque<BenchmarkExecution> = ConcurrentLinkedDeque()
-    val benchmarks: ConcurrentHashMap<String, KubernetesBenchmark> = ConcurrentHashMap()
-    var isUpdated = AtomicBoolean(false)
-    var executionID = AtomicInteger(0)
-
     /**
+     *
      * Runs the TheodoliteController forever.
      */
     fun run() {
+        sleep(5000) // wait until all states are correctly set
         while (true) {
-            try {
-                reconcile()
-                logger.info { "Theodolite is waiting for new matching benchmark and execution." }
-                logger.info { "Currently available executions: " }
-                executionsQueue.forEach {
-                    logger.info { "${it.name} : waiting for : ${it.benchmark}" }
-                }
-                logger.info { "Currently available benchmarks: " }
-                benchmarks.forEach {
-                    logger.info { it.key }
-                }
-                sleep(2000)
-            } catch (e: InterruptedException) {
-                logger.error { "Execution interrupted with error: $e." }
-            }
+            reconcile()
+            sleep(2000)
         }
     }
 
-    /**
-     * Ensures that the application state corresponds to the defined KubernetesBenchmarks and BenchmarkExecutions.
-     *
-     * @see KubernetesBenchmark
-     * @see BenchmarkExecution
-     */
-    @Synchronized
     private fun reconcile() {
-        while (executionsQueue.isNotEmpty()) {
-            val execution = executionsQueue.peek()
-            val benchmark = benchmarks[execution.benchmark]
-
-            if (benchmark == null) {
-                logger.debug { "No benchmark found for execution ${execution.name}." }
-                sleep(1000)
+        do {
+            val execution = getNextExecution()
+            if (execution != null) {
+                val benchmark = getBenchmarks()
+                    .firstOrNull { it.name == execution.benchmark }
+                if (benchmark != null) {
+                    runExecution(execution, benchmark)
+                }
             } else {
-                runExecution(execution, benchmark)
+                logger.info { "Could not find executable execution." }
             }
-        }
+        } while (execution != null)
     }
 
     /**
      * Execute a benchmark with a defined KubernetesBenchmark and BenchmarkExecution
      *
-     * @see KubernetesBenchmark
      * @see BenchmarkExecution
      */
-    @Synchronized
-    fun runExecution(execution: BenchmarkExecution, benchmark: KubernetesBenchmark) {
-        execution.executionId = executionID.getAndSet(executionID.get() + 1)
-        isUpdated.set(false)
-        benchmark.path = path
-        logger.info { "Start execution ${execution.name} with benchmark ${benchmark.name}." }
-        executor = TheodoliteExecutor(config = execution, kubernetesBenchmark = benchmark)
-        executor.run()
+    private fun runExecution(execution: BenchmarkExecution, benchmark: KubernetesBenchmark) {
+        setAdditionalLabels(execution.name,
+            "deployed-for-execution",
+            benchmark.appResource + benchmark.loadGenResource,
+            execution)
+        setAdditionalLabels(benchmark.name,
+            "deployed-for-benchmark",
+            benchmark.appResource + benchmark.loadGenResource,
+            execution)
+        setAdditionalLabels("theodolite",
+            "app.kubernetes.io/created-by",
+            benchmark.appResource + benchmark.loadGenResource,
+            execution)
+
+        executionStateHandler.setExecutionState(execution.name, States.RUNNING)
+        executionStateHandler.startDurationStateTimer(execution.name)
 
         try {
-            if (!isUpdated.get()) {
-                this.executionsQueue.removeIf { e -> e.name == execution.name }
-                client.customResource(executionContext).delete(client.namespace, execution.metadata.name)
+            executor = TheodoliteExecutor(execution, benchmark)
+            executor.run()
+            when (executionStateHandler.getExecutionState(execution.name)) {
+                States.RESTART -> runExecution(execution, benchmark)
+                States.RUNNING -> {
+                    executionStateHandler.setExecutionState(execution.name, States.FINISHED)
+                    logger.info { "Execution of ${execution.name} is finally stopped." }
+                }
             }
         } catch (e: Exception) {
-            logger.warn { "Deletion skipped." }
+            logger.error { "Failure while executing execution ${execution.name} with benchmark ${benchmark.name}." }
+            logger.error { "Problem is: $e" }
+            executionStateHandler.setExecutionState(execution.name, States.FAILURE)
         }
+        executionStateHandler.stopDurationStateTimer()
+    }
 
-        logger.info { "Execution of ${execution.name} is finally stopped." }
+    @Synchronized
+    fun stop(restart: Boolean = false) {
+        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)
+    }
+
+    /**
+     * @return all available [BenchmarkCRD]s
+     */
+    private fun getBenchmarks(): List<KubernetesBenchmark> {
+        return this.benchmarkCRDClient
+            .inNamespace(namespace)
+            .list()
+            .items
+            .map { it.spec.name = it.metadata.name; it }
+            .map { it.spec.path = path; it }
+            .map { it.spec }
     }
 
     /**
-     * @return true if the TheodoliteExecutor of this controller is initialized. Else returns false.
+     * Get the [BenchmarkExecution] for the next run. Which [BenchmarkExecution]
+     * is selected for the next execution depends on three points:
      *
-     * @see TheodoliteExecutor
+     * 1. Only executions are considered for which a matching benchmark is available on the cluster
+     * 2. The Status of the execution must be [States.PENDING] or [States.RESTART]
+     * 3. Of the remaining [BenchmarkCRD], those with status [States.RESTART] are preferred,
+     * then, if there is more than one, the oldest execution is chosen.
+     *
+     * @return the next execution or null
      */
-    @Synchronized
-    fun isInitialized(): Boolean {
-        return ::executor.isInitialized
+    private fun getNextExecution(): BenchmarkExecution? {
+        val availableBenchmarkNames = getBenchmarks()
+            .map { it.name }
+
+        return executionCRDClient
+            .inNamespace(namespace)
+            .list()
+            .items
+            .asSequence()
+            .map { it.spec.name = it.metadata.name; it }
+            .filter {
+                it.status.executionState == States.PENDING.value ||
+                        it.status.executionState == States.RESTART.value
+            }
+            .filter { availableBenchmarkNames.contains(it.spec.benchmark) }
+            .sortedWith(stateComparator().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 {
+        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-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt
index 5e15a4a80e67f47a42d605d4af39102927139331..0d55b0c1c1c76dba226d34554e0d96a3df77c1c3 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt
@@ -1,13 +1,13 @@
 package theodolite.execution.operator
 
 import io.fabric8.kubernetes.client.DefaultKubernetesClient
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
+import io.fabric8.kubernetes.client.dsl.MixedOperation
+import io.fabric8.kubernetes.client.dsl.Resource
 import io.fabric8.kubernetes.internal.KubernetesDeserializer
 import mu.KotlinLogging
-import theodolite.benchmark.BenchmarkExecution
-import theodolite.benchmark.BenchmarkExecutionList
-import theodolite.benchmark.KubernetesBenchmark
-import theodolite.benchmark.KubernetesBenchmarkList
 import theodolite.k8s.K8sContextFactory
+import theodolite.model.crd.*
 
 
 private const val DEFAULT_NAMESPACE = "default"
@@ -16,7 +16,7 @@ private const val EXECUTION_SINGULAR = "execution"
 private const val EXECUTION_PLURAL = "executions"
 private const val BENCHMARK_SINGULAR = "benchmark"
 private const val BENCHMARK_PLURAL = "benchmarks"
-private const val API_VERSION = "v1alpha1"
+private const val API_VERSION = "v1"
 private const val RESYNC_PERIOD = 10 * 60 * 1000.toLong()
 private const val GROUP = "theodolite.com"
 private val logger = KotlinLogging.logger {}
@@ -28,47 +28,95 @@ private val logger = KotlinLogging.logger {}
  */
 class TheodoliteOperator {
     private val namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
+    val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
+
+
+    fun start() {
+        LeaderElector(
+            client = client,
+            name = "theodolite-operator"
+        )
+            .getLeadership(::startOperator)
+    }
 
     /**
      * Start the operator.
      */
-    fun start() {
+   private fun startOperator() {
         logger.info { "Using $namespace as namespace." }
-        val client = DefaultKubernetesClient().inNamespace(namespace)
+        client.use {
+            KubernetesDeserializer.registerCustomKind(
+                "$GROUP/$API_VERSION",
+                EXECUTION_SINGULAR,
+                ExecutionCRD::class.java
+            )
 
-        KubernetesDeserializer.registerCustomKind(
-            "$GROUP/$API_VERSION",
-            EXECUTION_SINGULAR,
-            BenchmarkExecution::class.java
-        )
+            KubernetesDeserializer.registerCustomKind(
+                "$GROUP/$API_VERSION",
+                BENCHMARK_SINGULAR,
+                BenchmarkCRD::class.java
+            )
 
-        KubernetesDeserializer.registerCustomKind(
-            "$GROUP/$API_VERSION",
-            BENCHMARK_SINGULAR,
-            KubernetesBenchmark::class.java
-        )
+            val contextFactory = K8sContextFactory()
+            val executionContext = contextFactory.create(API_VERSION, SCOPE, GROUP, EXECUTION_PLURAL)
+            val benchmarkContext = contextFactory.create(API_VERSION, SCOPE, GROUP, BENCHMARK_PLURAL)
 
-        val contextFactory = K8sContextFactory()
-        val executionContext = contextFactory.create(API_VERSION, SCOPE, GROUP, EXECUTION_PLURAL)
-        val benchmarkContext = contextFactory.create(API_VERSION, SCOPE, GROUP, BENCHMARK_PLURAL)
+            val executionCRDClient: MixedOperation<
+                    ExecutionCRD,
+                    BenchmarkExecutionList,
+                    DoneableExecution,
+                    Resource<ExecutionCRD, DoneableExecution>>
+                = client.customResources(
+                    executionContext,
+                    ExecutionCRD::class.java,
+                    BenchmarkExecutionList::class.java,
+                    DoneableExecution::class.java)
 
-        val appResource = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
-        val controller = TheodoliteController(client = client, executionContext = executionContext, path = appResource)
+            val benchmarkCRDClient: MixedOperation<
+                    BenchmarkCRD,
+                    KubernetesBenchmarkList,
+                    DoneableBenchmark,
+                    Resource<BenchmarkCRD, DoneableBenchmark>>
+                = client.customResources(
+                    benchmarkContext,
+                    BenchmarkCRD::class.java,
+                    KubernetesBenchmarkList::class.java,
+                    DoneableBenchmark::class.java)
 
-        val informerFactory = client.informers()
-        val informerExecution = informerFactory.sharedIndexInformerForCustomResource(
-            executionContext, BenchmarkExecution::class.java,
-            BenchmarkExecutionList::class.java, RESYNC_PERIOD
-        )
-        val informerBenchmark = informerFactory.sharedIndexInformerForCustomResource(
-            benchmarkContext, KubernetesBenchmark::class.java,
-            KubernetesBenchmarkList::class.java, RESYNC_PERIOD
-        )
+            val executionStateHandler = ExecutionStateHandler(
+                context = executionContext,
+                client = client)
+
+            val appResource = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
+            val controller =
+                TheodoliteController(
+                    namespace = client.namespace,
+                    path = appResource,
+                    benchmarkCRDClient = benchmarkCRDClient,
+                    executionCRDClient = executionCRDClient,
+                    executionStateHandler = executionStateHandler)
+
+            val informerFactory = client.informers()
+            val informerExecution = informerFactory.sharedIndexInformerForCustomResource(
+                executionContext,
+                ExecutionCRD::class.java,
+                BenchmarkExecutionList::class.java,
+                RESYNC_PERIOD
+            )
+
+            informerExecution.addEventHandler(ExecutionHandler(
+                controller = controller,
+                stateHandler = executionStateHandler))
+
+            ClusterSetup(
+                executionCRDClient = executionCRDClient,
+                benchmarkCRDClient = benchmarkCRDClient,
+                client = client
+            ).clearClusterState()
 
-        informerExecution.addEventHandler(ExecutionHandler(controller))
-        informerBenchmark.addEventHandler(BenchmarkEventHandler(controller))
-        informerFactory.startAllRegisteredInformers()
+            informerFactory.startAllRegisteredInformers()
+            controller.run()
 
-        controller.run()
+        }
     }
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt
index 4950cee225e103ff095def91de64471ec1894a79..56452d74968db0fd4c939f44f3ed8a7abbe7b928 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt
@@ -53,4 +53,9 @@ class ServiceMonitorWrapper(private val serviceMonitor: Map<String, String>) : C
         val smAsMap = this.serviceMonitor["metadata"]!! as Map<String, String>
         return smAsMap["name"]!!
     }
+
+    fun getLabels(): Map<String, String>{
+        val smAsMap = this.serviceMonitor["metadata"]!! as Map<String, String>
+        return smAsMap["labels"]!! as Map<String, String>
+    }
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/BenchmarkCRD.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/BenchmarkCRD.kt
new file mode 100644
index 0000000000000000000000000000000000000000..326aa10a21bebd913eaafcb8315188288ae97ff1
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/BenchmarkCRD.kt
@@ -0,0 +1,11 @@
+package theodolite.model.crd
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import io.fabric8.kubernetes.api.model.Namespaced
+import io.fabric8.kubernetes.client.CustomResource
+import theodolite.benchmark.KubernetesBenchmark
+
+@JsonDeserialize
+class BenchmarkCRD(
+    var spec: KubernetesBenchmark = KubernetesBenchmark()
+) : CustomResource(), Namespaced
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/BenchmarkExecutionList.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/BenchmarkExecutionList.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2b2dcc07f9c37f1712109e3d092f2db0c139e1c8
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/BenchmarkExecutionList.kt
@@ -0,0 +1,5 @@
+package theodolite.model.crd
+
+import io.fabric8.kubernetes.client.CustomResourceList
+
+class BenchmarkExecutionList : CustomResourceList<ExecutionCRD>()
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/DoneableBenchmark.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/DoneableBenchmark.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e00e8268b2ec8eba17b3706feb3940eded1b2b0c
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/DoneableBenchmark.kt
@@ -0,0 +1,7 @@
+package theodolite.model.crd
+
+import io.fabric8.kubernetes.api.builder.Function
+import io.fabric8.kubernetes.client.CustomResourceDoneable
+
+class DoneableBenchmark(resource: BenchmarkCRD, function: Function<BenchmarkCRD, BenchmarkCRD>) :
+    CustomResourceDoneable<BenchmarkCRD>(resource, function)
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/DoneableExecution.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/DoneableExecution.kt
new file mode 100644
index 0000000000000000000000000000000000000000..be07725b405c29a0d9000b6e6ec455536ad111fb
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/DoneableExecution.kt
@@ -0,0 +1,8 @@
+package theodolite.execution.operator
+
+import io.fabric8.kubernetes.client.CustomResourceDoneable
+import io.fabric8.kubernetes.api.builder.Function
+import theodolite.model.crd.ExecutionCRD
+
+class DoneableExecution(resource: ExecutionCRD, function: Function<ExecutionCRD, ExecutionCRD>) :
+    CustomResourceDoneable<ExecutionCRD>(resource, function)
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/ExecutionCRD.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/ExecutionCRD.kt
new file mode 100644
index 0000000000000000000000000000000000000000..79a387cee250d3abf0fdb576a5f0f33424596792
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/ExecutionCRD.kt
@@ -0,0 +1,13 @@
+package theodolite.model.crd
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.Namespaced
+import io.fabric8.kubernetes.client.CustomResource
+import theodolite.benchmark.BenchmarkExecution
+
+@JsonDeserialize
+class ExecutionCRD(
+    var spec: BenchmarkExecution = BenchmarkExecution(),
+    var status: ExecutionStatus = ExecutionStatus()
+    ) : CustomResource(), Namespaced
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/ExecutionStatus.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/ExecutionStatus.kt
new file mode 100644
index 0000000000000000000000000000000000000000..43e9035b3120eb22304576f2006092eec376b6d2
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/ExecutionStatus.kt
@@ -0,0 +1,13 @@
+package theodolite.model.crd
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.Namespaced
+import io.fabric8.kubernetes.client.CustomResource
+
+@JsonDeserialize
+class ExecutionStatus(): KubernetesResource, CustomResource(), Namespaced {
+    var executionState: String = ""
+    var executionDuration: String = "-"
+
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/KubernetesBenchmarkList.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/KubernetesBenchmarkList.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8ad0a493d948bf5f78741052100766dcf6e316ec
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/KubernetesBenchmarkList.kt
@@ -0,0 +1,5 @@
+package theodolite.model.crd
+
+import io.fabric8.kubernetes.client.CustomResourceList
+
+class KubernetesBenchmarkList : CustomResourceList<BenchmarkCRD>()
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/States.kt b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/States.kt
new file mode 100644
index 0000000000000000000000000000000000000000..79af297915b6703b209acb0c13913482e54db2be
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/model/crd/States.kt
@@ -0,0 +1,11 @@
+package theodolite.model.crd
+
+enum class States(val value: String) {
+    RUNNING("RUNNING"),
+    PENDING("PENDING"),
+    FAILURE("FAILURE"),
+    FINISHED("FINISHED"),
+    RESTART("RESTART"),
+    INTERRUPTED("INTERRUPTED"),
+    NO_STATE("NoState")
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
index c0d17244b6a7a3f37b8d8a57713659b85b9b65b1..df80e9cbd2503685a7dbed35db5319920dfc42cb 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
@@ -20,7 +20,5 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
  *
  */
 abstract class AbstractPatcher(
-    k8sResource: KubernetesResource,
-    container: String? = null,
-    variableName: String? = null
+    k8sResource: KubernetesResource
 ) : Patcher
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
index b640df1da2ca1c139bb5b02e9e42bad9e7d08d74..416aec74a3af9b74594f5e6cd018682bf91cbf63 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
@@ -16,7 +16,7 @@ class EnvVarPatcher(
     private val k8sResource: KubernetesResource,
     private val container: String,
     private val variableName: String
-) : AbstractPatcher(k8sResource, container, variableName) {
+) : AbstractPatcher(k8sResource) {
 
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
index b29d8d9925311aa25b7336dcd6805783ca62c3e7..8f6753372076c119324dc962112928253633b6b0 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
@@ -11,7 +11,7 @@ import io.fabric8.kubernetes.api.model.apps.StatefulSet
  * @param container Container to be patched.
  */
 class ImagePatcher(private val k8sResource: KubernetesResource, private val container: String) :
-    AbstractPatcher(k8sResource, container) {
+    AbstractPatcher(k8sResource) {
 
     override fun <String> patch(imagePath: String) {
         if (k8sResource is Deployment) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/LabelPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5ee5807cd8378c9f2bbd62435203208d61131f15
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
@@ -0,0 +1,49 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.ConfigMap
+import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.Service
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.api.model.apps.StatefulSet
+import io.fabric8.kubernetes.client.CustomResource
+
+class LabelPatcher(private val k8sResource: KubernetesResource, val variableName: String) :
+    AbstractPatcher(k8sResource) {
+
+    override fun <String> patch(labelValue: String) {
+        if(labelValue is kotlin.String){
+            when(k8sResource){
+                is Deployment -> {
+                    if (k8sResource.metadata.labels == null){
+                        k8sResource.metadata.labels = mutableMapOf()
+                    }
+                    k8sResource.metadata.labels[this.variableName] = labelValue
+                }
+                is StatefulSet -> {
+                    if (k8sResource.metadata.labels == null){
+                        k8sResource.metadata.labels = mutableMapOf()
+                    }
+                    k8sResource.metadata.labels[this.variableName] = labelValue
+                }
+                is Service -> {
+                    if (k8sResource.metadata.labels == null){
+                        k8sResource.metadata.labels = mutableMapOf()
+                    }
+                    k8sResource.metadata.labels[this.variableName] = labelValue
+                }
+                is ConfigMap -> {
+                    if (k8sResource.metadata.labels == null){
+                        k8sResource.metadata.labels = mutableMapOf()
+                    }
+                    k8sResource.metadata.labels[this.variableName] = labelValue
+                }
+                is CustomResource -> {
+                    if (k8sResource.metadata.labels == null){
+                        k8sResource.metadata.labels = mutableMapOf()
+                    }
+                    k8sResource.metadata.labels[this.variableName] = labelValue
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
index 0a668a908e66577f96ea1268b85a38ad73bb16a7..0e8cd553a6c6a9ed6fa2c8cc1b84e4cfebe79d73 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
@@ -10,7 +10,7 @@ import io.fabric8.kubernetes.api.model.apps.Deployment
  * @param variableName The `label-key` of the node for which the `label-value` is to be patched.
  */
 class NodeSelectorPatcher(private val k8sResource: KubernetesResource, private val variableName: String) :
-    AbstractPatcher(k8sResource, variableName) {
+    AbstractPatcher(k8sResource) {
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
             k8sResource.spec.template.spec.nodeSelector = mapOf(variableName to value as kotlin.String)
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
index d7136740a7e17f956eed16bc6e3fcd4954ab91b8..65489a96974ad566fe7cbd88cf6ff7fb49135e1d 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
@@ -4,16 +4,17 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import kotlin.math.pow
 
-private const val NUM_SENSORS = 4.0
-private const val LOAD_GEN_MAX_RECORDS = 150000
-
-class NumNestedGroupsLoadGeneratorReplicaPatcher(private val k8sResource: KubernetesResource) :
+class NumNestedGroupsLoadGeneratorReplicaPatcher(
+    private val k8sResource: KubernetesResource,
+    private val numSensors: String,
+    private val loadGenMaxRecords: String
+    ) :
     AbstractPatcher(k8sResource) {
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
             if (value is kotlin.String) {
-                val approxNumSensors = NUM_SENSORS.pow(Integer.parseInt(value).toDouble())
-                val loadGenInstances = (approxNumSensors + LOAD_GEN_MAX_RECORDS - 1) / LOAD_GEN_MAX_RECORDS
+                val approxNumSensors =  numSensors.toDouble().pow(Integer.parseInt(value).toDouble())
+                val loadGenInstances = (approxNumSensors + loadGenMaxRecords.toDouble() - 1) / loadGenMaxRecords.toDouble()
                 this.k8sResource.spec.replicas = loadGenInstances.toInt()
             }
         }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
index d29280a648cd4c912b8e2717b51c4f9c3f8a2271..f6a06324e36d7942d3944a492fee263f428376c1 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
@@ -3,14 +3,16 @@ package theodolite.patcher
 import io.fabric8.kubernetes.api.model.KubernetesResource
 import io.fabric8.kubernetes.api.model.apps.Deployment
 
-private const val LOAD_GEN_MAX_RECORDS = 150000
 
-class NumSensorsLoadGeneratorReplicaPatcher(private val k8sResource: KubernetesResource) :
+class NumSensorsLoadGeneratorReplicaPatcher(
+    private val k8sResource: KubernetesResource,
+    private val loadGenMaxRecords: String
+) :
     AbstractPatcher(k8sResource) {
     override fun <String> patch(value: String) {
         if (k8sResource is Deployment) {
             if (value is kotlin.String) {
-                val loadGenInstances = (Integer.parseInt(value) + LOAD_GEN_MAX_RECORDS - 1) / LOAD_GEN_MAX_RECORDS
+                val loadGenInstances = (Integer.parseInt(value) + loadGenMaxRecords.toInt() - 1) / loadGenMaxRecords.toInt()
                 this.k8sResource.spec.replicas = loadGenInstances
             }
         }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt
index bcb568f716449cb1981112ab23a81411a0f7c54d..d5a6f3821d2688651475625506a78efc6061ab82 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherDefinitionFactory.kt
@@ -21,8 +21,7 @@ class PatcherDefinitionFactory {
      *     value of the requiredType.
      */
     fun createPatcherDefinition(requiredType: String, patcherTypes: List<TypeName>): List<PatcherDefinition> {
-        return patcherTypes
-            .filter { type -> type.typeName == requiredType }
-            .flatMap { type -> type.patchers }
+        return patcherTypes.firstOrNull() { type -> type.typeName == requiredType }
+            ?.patchers ?: throw IllegalArgumentException("typeName $requiredType not found.")
     }
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
index 2ee1f6c7b46322cb0f8de03c37aabe64ccf0ba5a..45e50113c964d671962fadc718994a29b2da81f4 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
@@ -1,6 +1,8 @@
 package theodolite.patcher
 
 import io.fabric8.kubernetes.api.model.KubernetesResource
+import theodolite.util.DeploymentFailedException
+import theodolite.util.InvalidPatcherConfigurationException
 import theodolite.util.PatcherDefinition
 
 /**
@@ -27,25 +29,56 @@ class PatcherFactory {
         k8sResources: List<Pair<String, KubernetesResource>>
     ): Patcher {
         val resource =
-            k8sResources.filter { it.first == patcherDefinition.resource }.map { resource -> resource.second }[0]
-        return when (patcherDefinition.type) {
-            "ReplicaPatcher" -> ReplicaPatcher(resource)
-            "NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher(resource)
-            "NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher(resource)
-            "EnvVarPatcher" -> EnvVarPatcher(resource, patcherDefinition.container, patcherDefinition.variableName)
-            "NodeSelectorPatcher" -> NodeSelectorPatcher(resource, patcherDefinition.variableName)
-            "ResourceLimitPatcher" -> ResourceLimitPatcher(
-                resource,
-                patcherDefinition.container,
-                patcherDefinition.variableName
-            )
-            "ResourceRequestPatcher" -> ResourceRequestPatcher(
-                resource,
-                patcherDefinition.container,
-                patcherDefinition.variableName
-            )
-            "SchedulerNamePatcher" -> SchedulerNamePatcher(resource)
-            else -> throw IllegalArgumentException("Patcher type ${patcherDefinition.type} not found")
+            k8sResources.filter { it.first == patcherDefinition.resource }
+                .map { resource -> resource.second }
+                .firstOrNull()
+                ?: throw DeploymentFailedException("Could not find resource ${patcherDefinition.resource}")
+
+        return try {
+            when (patcherDefinition.type) {
+                "ReplicaPatcher" -> ReplicaPatcher(
+                    k8sResource = resource
+                )
+                "NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher(
+                    k8sResource = resource,
+                    loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"] !!,
+                    numSensors = patcherDefinition.properties["numSensors"] !!
+                )
+                "NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher(
+                    k8sResource = resource,
+                    loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"] !!
+                )
+                "EnvVarPatcher" -> EnvVarPatcher(
+                    k8sResource = resource,
+                    container = patcherDefinition.properties["container"] !!,
+                    variableName = patcherDefinition.properties["variableName"] !!
+                )
+                "NodeSelectorPatcher" -> NodeSelectorPatcher(
+                    k8sResource = resource,
+                    variableName = patcherDefinition.properties["variableName"] !!
+                )
+                "ResourceLimitPatcher" -> ResourceLimitPatcher(
+                    k8sResource = resource,
+                    container = patcherDefinition.properties["container"] !!,
+                    limitedResource = patcherDefinition.properties["limitedResource"] !!
+                )
+                "ResourceRequestPatcher" -> ResourceRequestPatcher(
+                    k8sResource = resource,
+                    container = patcherDefinition.properties["container"] !!,
+                    requestedResource = patcherDefinition.properties["requestedResource"] !!
+                )
+                "SchedulerNamePatcher" -> SchedulerNamePatcher(
+                    k8sResource = resource
+                )
+                "LabelPatcher" -> LabelPatcher(
+                    k8sResource = resource,
+                    variableName = patcherDefinition.properties["variableName"] !!
+                )
+                else -> throw InvalidPatcherConfigurationException("Patcher type ${patcherDefinition.type} not found.")
+            }
+        } catch (e: Exception) {
+            throw InvalidPatcherConfigurationException("Could not create patcher with type ${patcherDefinition.type}" +
+                    " Probably a required patcher argument was not specified." )
         }
     }
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
index 30f82e804f23b770457ec968f25ba7c00d72aefd..1a6fa35a944d00634ec0607b0bff34f4cb9d9b9c 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
@@ -18,7 +18,7 @@ class ResourceLimitPatcher(
     private val k8sResource: KubernetesResource,
     private val container: String,
     private val limitedResource: String
-) : AbstractPatcher(k8sResource, container, limitedResource) {
+) : AbstractPatcher(k8sResource) {
 
     override fun <String> patch(value: String) {
         when (k8sResource) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
index 24b2a6d40525f16448b77c50fba8aba0969d075a..9bf8c3c72f656d326ca3070cd5843778e5cdff42 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
@@ -18,7 +18,7 @@ class ResourceRequestPatcher(
     private val k8sResource: KubernetesResource,
     private val container: String,
     private val requestedResource: String
-) : AbstractPatcher(k8sResource, container, requestedResource) {
+) : AbstractPatcher(k8sResource) {
 
     override fun <String> patch(value: String) {
         when (k8sResource) {
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/DeploymentFailedException.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/DeploymentFailedException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0e276d7de4e205a75eb309a71a793e70f7565ea4
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/DeploymentFailedException.kt
@@ -0,0 +1,5 @@
+package theodolite.util
+
+
+class DeploymentFailedException(message:String): Exception(message) {
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/IOHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/IOHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8d379fcf0543257edafd2e45383a02ba0254563d
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/IOHandler.kt
@@ -0,0 +1,94 @@
+package theodolite.util
+
+import com.google.gson.GsonBuilder
+import mu.KotlinLogging
+import java.io.File
+import java.io.PrintWriter
+
+private val logger = KotlinLogging.logger {}
+
+/**
+ * The IOHandler handles most common I/O operations within the Theodolite framework
+ */
+class IOHandler {
+
+    /**
+     * The location in which Theodolite store result and configuration file are depends on
+     * the values of the environment variables `RESULT_FOLDER` and `CREATE_RESULTS_FOLDER`
+     *
+     * @return the URL of the result folder
+     */
+    fun getResultFolderURL(): String {
+        var resultsFolder: String = System.getenv("RESULTS_FOLDER") ?: ""
+        val createResultsFolder = System.getenv("CREATE_RESULTS_FOLDER") ?: "false"
+
+        if (resultsFolder != ""){
+            logger.info { "RESULT_FOLDER: $resultsFolder" }
+            val directory = File(resultsFolder)
+            if (!directory.exists()) {
+                logger.error { "Folder $resultsFolder does not exist" }
+                if (createResultsFolder.toBoolean()) {
+                    directory.mkdirs()
+                } else {
+                    throw IllegalArgumentException("Result folder not found")
+                }
+            }
+            resultsFolder += "/"
+        }
+        return  resultsFolder
+    }
+
+    /**
+     * Read a file as String
+     *
+     * @param fileURL the URL of the file
+     * @return The content of the file as String
+     */
+    fun readFileAsString(fileURL: String): String {
+        return File(fileURL).inputStream().readBytes().toString(Charsets.UTF_8).trim()
+    }
+
+    /**
+     * Creates a JSON string of the given object and store them to file
+     *
+     * @param T class of the object to save
+     * @param objectToSave object which should be saved as file
+     * @param fileURL the URL of the file
+     */
+    fun <T> writeToJSONFile(objectToSave: T, fileURL: String) {
+        val gson = GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create()
+        writeStringToTextFile(fileURL, gson.toJson(objectToSave))
+    }
+
+    /**
+     * Write to CSV file
+     *
+     * @param fileURL the URL of the file
+     * @param data  the data to write in the file, as list of list, each subList corresponds to a row in the CSV file
+     * @param columns columns of the CSV file
+     */
+    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=","))
+            data.forEach {
+                pw.println(it.joinToString(separator=","))
+            }
+        }
+        logger.info { "Wrote CSV file: $fileURL to ${outputFile.absolutePath}." }
+    }
+
+    /**
+     * Write to text file
+     *
+     * @param fileURL the URL of the file
+     * @param data the data to write in the file as String
+     */
+    fun writeStringToTextFile(fileURL: String, data: String) {
+        val outputFile = File("$fileURL")
+        outputFile.printWriter().use {
+                it.println(data)
+        }
+        logger.info { "Wrote txt file: $fileURL to ${outputFile.absolutePath}." }
+    }
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c103ef1f35a1b3ffa56dad50c7cf6c1db51eb57f
--- /dev/null
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt
@@ -0,0 +1,5 @@
+package theodolite.util
+
+class InvalidPatcherConfigurationException(message:String): Exception(message) {
+}
+
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt
index 398ff90bed8f48683321e2375458b3a065c39463..4e72ccb0d86749a6538c26556241ac114ef8d9a4 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/KafkaConfig.kt
@@ -28,6 +28,7 @@ class KafkaConfig {
      * Wrapper for a topic definition.
      */
     @RegisterForReflection
+    @JsonDeserialize
     class TopicWrapper {
         /**
          * The topic name
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt
index b24f887d6ff6e3096a2e740f541861d76804775b..6ec0cce36751ec0343d40aa49fefa44f4c7fc918 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/PatcherDefinition.kt
@@ -1,6 +1,7 @@
 package theodolite.util
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import com.fasterxml.jackson.databind.annotation.JsonSerialize
 import io.quarkus.runtime.annotations.RegisterForReflection
 
 /**
@@ -19,13 +20,6 @@ class PatcherDefinition {
      */
     lateinit var resource: String
 
-    /**
-     * The container which the patcher is applied to
-     */
-    lateinit var container: String
-
-    /**
-     * The variable name for the patcher
-     */
-    lateinit var variableName: String
+    @JsonSerialize
+    lateinit var properties: MutableMap<String, String>
 }
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/util/PrometheusResponse.kt b/theodolite-quarkus/src/main/kotlin/theodolite/util/PrometheusResponse.kt
index d1d59c482e64fd14c4744d8fcd606f286da24fb4..846577387c425e920da1c2fca1f972c880e1540a 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/util/PrometheusResponse.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/util/PrometheusResponse.kt
@@ -1,6 +1,7 @@
 package theodolite.util
 
 import io.quarkus.runtime.annotations.RegisterForReflection
+import java.util.*
 
 /**
  * This class corresponds to the JSON response format of a Prometheus
@@ -17,6 +18,27 @@ data class PrometheusResponse(
      */
     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 ], ... ]`
+     */
+    fun getResultAsList(): List<List<String>> {
+        val group = data?.result?.get(0)?.metric?.group.toString()
+        val values = data?.result?.get(0)?.values
+        val result = mutableListOf<List<String>>()
+
+        if (values != null) {
+            for (value in values) {
+                val valueList = value as List<*>
+                val timestamp = (valueList[0] as Double).toLong().toString()
+                val value = valueList[1].toString()
+                result.add(listOf(group, timestamp, value))
+            }
+        }
+        return Collections.unmodifiableList(result)
+    }
+}
 
 /**
  * Description of Prometheus data.
@@ -56,4 +78,5 @@ data class PromResult(
 @RegisterForReflection
 data class PromMetric(
     var group: String? = null
-)
\ No newline at end of file
+)
+
diff --git a/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml b/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml
index 8fb3de1928f051d338a78ee58da074a73ef933c1..b76821f6e7cca5408f604ba9bbf83cf1b43a37de 100644
--- a/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/benchmarkCRD.yaml
@@ -1,13 +1,117 @@
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   name: benchmarks.theodolite.com
 spec:
   group: theodolite.com
-  version: v1alpha1
   names:
     kind: benchmark
     plural: benchmarks
-  scope: Namespaced
-  subresources:
-    status: {}
\ No newline at end of file
+    shortNames:
+      - bench
+  versions:
+  - name: v1
+    served: true
+    storage: true
+    schema:
+      openAPIV3Schema:
+        type: object
+        required: ["spec"]
+        properties:
+          spec:
+            type: object
+            required: []
+            properties:
+              name:
+                type: string
+              appResource:
+                type: array
+                minItems: 1
+                items:
+                  type: string
+              loadGenResource:
+                type: array
+                minItems: 1
+                items:
+                  type: string
+              resourceTypes:
+                type: array
+                minItems: 1
+                items:
+                  type: object
+                  properties:
+                    typeName:
+                      type: string
+                    patchers:
+                      type: array
+                      minItems: 1
+                      items:
+                        type: object
+                        properties:
+                          type:
+                            type: string
+                            default: ""
+                          resource:
+                            type: string
+                            default: ""
+                          properties:
+                            type: object
+                            additionalProperties: true
+                            x-kubernetes-map-type: "granular"
+                            default: {}
+              loadTypes:
+                type: array
+                minItems: 1
+                items:
+                  type: object
+                  properties:
+                    typeName:
+                      type: string
+                    patchers:
+                      type: array
+                      minItems: 1
+                      items:
+                        type: object
+                        properties:
+                          type:
+                            type: string
+                            default: ""
+                          resource:
+                            type: string
+                            default: ""
+                          properties:
+                            type: object
+                            additionalProperties: true
+                            x-kubernetes-map-type: "granular"
+                            default: {}
+              kafkaConfig:
+                type: object
+                properties:
+                  bootstrapServer:
+                    type: string
+                  topics:
+                    type: array
+                    minItems: 1
+                    items:
+                      type: object
+                      required: []
+                      properties:
+                        name:
+                          type: string
+                          default: ""
+                        numPartitions:
+                          type: integer
+                          default: 0
+                        replicationFactor:
+                          type: integer
+                          default: 0
+                        removeOnly:
+                          type: boolean
+                          default: false
+    additionalPrinterColumns:
+    - name: Age
+      type: date
+      jsonPath: .metadata.creationTimestamp
+    subresources:
+      status: {}
+  scope: Namespaced
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml b/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml
index 19ec972be8236fbdcad123e9c9ef63945bb53d16..7a728d97c52a84d81bcc44fd9f20c56e6b574527 100644
--- a/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/example-benchmark-k8s-resource.yaml
@@ -1,31 +1,39 @@
-apiVersion: theodolite.com/v1alpha1
+apiVersion: theodolite.com/v1
 kind: benchmark
 metadata:
   name: uc1-kstreams
-appResource:
-  - "uc1-kstreams-deployment.yaml"
-  - "aggregation-service.yaml"
-  - "jmx-configmap.yaml"
-loadGenResource:
-  - "uc1-load-generator-deployment.yaml"
-  - "uc1-load-generator-service.yaml"
-resourceTypes:
-  - typeName: "Instances"
-    patchers:
-      - type: "ReplicaPatcher"
-        resource: "uc1-kstreams-deployment.yaml"
-loadTypes:
-  - typeName: "NumSensors"
-    patchers:
-      - type: "EnvVarPatcher"
-        resource: "uc1-load-generator-deployment.yaml"
-        container: "workload-generator"
-        variableName: "NUM_SENSORS"
-kafkaConfig:
-  bootstrapServer: "localhost:31290"
-  topics:
-    - name: "input"
-      numPartitions: 40
-      replicationFactor: 1
-    - name: "theodolite-.*"
-      removeOnly: True
\ No newline at end of file
+spec:
+  name: test
+  appResource:
+    - "uc1-kstreams-deployment.yaml"
+    - "aggregation-service.yaml"
+    - "jmx-configmap.yaml"
+  loadGenResource:
+    - "uc1-load-generator-deployment.yaml"
+    - "uc1-load-generator-service.yaml"
+    - "uc1-load-generator-service.yaml"
+  resourceTypes:
+    - typeName: "Instances"
+      patchers:
+        - type: "ReplicaPatcher"
+          resource: "uc1-kstreams-deployment.yaml"
+  loadTypes:
+    - typeName: "NumSensors"
+      patchers:
+        - type: "EnvVarPatcher"
+          resource: "uc1-load-generator-deployment.yaml"
+          properties:
+            container: "workload-generator"
+            variableName: "NUM_SENSORS"
+        - type: "NumSensorsLoadGeneratorReplicaPatcher"
+          resource: "uc1-load-generator-deployment.yaml"
+          properties:
+            loadGenMaxRecords: "15000"
+  kafkaConfig:
+    bootstrapServer: "localhost:31290"
+    topics:
+      - name: "input"
+        numPartitions: 40
+        replicationFactor: 1
+      - name: "theodolite-.*"
+        removeOnly: True
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml b/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml
index 7f76b1bca0db77df08861e0611487642e19bbc1a..b81bbcd442834136283dc080f5f6a79bbc1cd415 100644
--- a/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/example-execution-k8s-resource.yaml
@@ -1,38 +1,29 @@
-apiVersion: theodolite.com/v1alpha1
+apiVersion: theodolite.com/v1
 kind: execution
 metadata:
   name: theodolite-example-execution
-benchmark: "uc1-kstreams"
-load:
-  loadType: "NumSensors"
-  loadValues:
-    - 50000
-resources:
-  resourceType: "Instances"
-  resourceValues:
-    - 1
-slos:
-  - sloType: "lag trend"
-    threshold: 1000
-    prometheusUrl: "http://localhost:32656"
-    externalSloUrl: "http://localhost:80/evaluate-slope"
-    offset: 0
-    warmup: 0
-execution:
-  strategy: "LinearSearch"
-  duration: 60
-  repetitions: 1
-  delay: 30 # in seconds
-  restrictions:
-    - "LowerBound"
-configOverrides:
-  - patcher:
-      type: "NodeSelectorPatcher"
-      resource: "uc1-load-generator-deployment.yaml"
-      variableName: "env"
-    value: "prod"
-  - patcher:
-      type: "NodeSelectorPatcher"
-      resource: "uc1-kstreams-deployment.yaml"
-      variableName: "env"
-    value: "prod"
\ No newline at end of file
+spec:  
+  benchmark: uc1-kstreams
+  load:  
+    loadType: "NumSensors"
+    loadValues:
+      - 50000 
+  resources:
+    resourceType: "Instances"
+    resourceValues:
+      - 1
+  slos:
+    - sloType: "lag trend"
+      threshold: 1000
+      prometheusUrl: "http://localhost:32656"
+      externalSloUrl: "http://localhost:80/evaluate-slope"
+      offset: 0
+      warmup: 0
+  execution:
+    strategy: "LinearSearch"
+    duration: 60
+    repetitions: 1
+    loadGenerationDelay: 30 # in seconds
+    restrictions:
+      - "LowerBound"
+  configOverrides: []
\ No newline at end of file
diff --git a/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml b/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml
index 0bdb83c6201112a750bad41b81321b7a108a66fa..b984f3ebe5ca7c8868adb9d3593e5d87d73fc2bd 100644
--- a/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml
+++ b/theodolite-quarkus/src/main/resources/operator/executionCRD.yaml
@@ -1,13 +1,128 @@
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   name: executions.theodolite.com
 spec:
   group: theodolite.com
-  version: v1alpha1
   names:
     kind: execution
     plural: executions
-  scope: Namespaced
-  subresources:
-    status: {}
\ No newline at end of file
+    shortNames:
+      - exec
+  versions:
+  - name: v1
+    served: true
+    storage: true
+    schema:
+      openAPIV3Schema:
+        type: object
+        required: ["spec"]
+        properties:
+          spec:
+            type: object
+            required: ["benchmark", "load", "resources", "slos", "execution", "configOverrides"]
+            properties:
+              name:
+                type: string
+                default: ""
+              benchmark:
+                type: string
+              load: # definition of the load dimension
+                type: object
+                required: ["loadType", "loadValues"]
+                properties:
+                  loadType:
+                   type: string
+                  loadValues:
+                    type: array
+                    items:
+                      type: integer
+              resources: # definition of the resource dimension
+                type: object
+                required: ["resourceType", "resourceValues"]
+                properties:
+                  resourceType:
+                    type: string
+                  resourceValues:
+                    type: array
+                    items:
+                      type: integer
+              slos: # def of service level objectives
+                type: array
+                items:
+                  type: object
+                  required: ["sloType", "threshold", "prometheusUrl", "externalSloUrl", "offset", "warmup"]
+                  properties:
+                    sloType:
+                      type: string
+                    threshold:
+                      type: integer
+                    prometheusUrl:
+                      type: string
+                    externalSloUrl:
+                      type: string
+                    offset:
+                      type: integer
+                    warmup:
+                      type: integer
+              execution: # def execution config
+                type: object
+                required: ["strategy", "duration", "repetitions", "restrictions"]
+                properties:
+                  strategy:
+                    type: string
+                  duration:
+                    type: integer
+                  repetitions:
+                    type: integer
+                  loadGenerationDelay:
+                    type: integer
+                  restrictions:
+                    type: array
+                    items:
+                      type: string
+              configOverrides:
+                type: array
+                items:
+                  type: object
+                  properties:
+                    patcher:
+                      type: object
+                      properties:
+                        type:
+                          type: string
+                          default: ""
+                        resource:
+                          type: string
+                          default: ""
+                        properties:
+                          type: object
+                          additionalProperties: true
+                          x-kubernetes-map-type: "granular"
+                          default: {}
+                    value:
+                      type: string
+          status:
+            type: object
+            properties:
+              executionState:
+                description: ""
+                type: string
+              executionDuration:
+                description: "Duration of the execution in seconds"
+                type: string
+    additionalPrinterColumns:
+    - name: STATUS
+      type: string
+      description: State of the execution
+      jsonPath: .status.executionState
+    - name: Duration
+      type: string
+      description: Duration of the execution
+      jsonPath: .status.executionDuration
+    - name: Age
+      type: date
+      jsonPath: .metadata.creationTimestamp
+    subresources:
+      status: {}
+  scope: Namespaced
\ No newline at end of file
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt
index 726d4490b053b5c56f0a0387f54ad557d4c1865c..c2b30ab7eb23d60db39778218ad9d6a4c12799a6 100644
--- a/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/CompositeStrategyTest.kt
@@ -31,7 +31,7 @@ class CompositeStrategyTest {
         val results = Results()
         val benchmark = TestBenchmark()
         val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
-        val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0)
+        val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0, 5)
         val linearSearch = LinearSearch(benchmarkExecutor)
         val lowerBoundRestriction = LowerBoundRestriction(results)
         val strategy =
@@ -65,7 +65,7 @@ class CompositeStrategyTest {
         val benchmark = TestBenchmark()
         val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
         val benchmarkExecutorImpl =
-            TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0)
+            TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0, 0)
         val binarySearch = BinarySearch(benchmarkExecutorImpl)
         val lowerBoundRestriction = LowerBoundRestriction(results)
         val strategy =
@@ -98,7 +98,7 @@ class CompositeStrategyTest {
         val results = Results()
         val benchmark = TestBenchmark()
         val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
-        val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0)
+        val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, sloChecker, 0, 0,0)
         val binarySearch = BinarySearch(benchmarkExecutor)
         val lowerBoundRestriction = LowerBoundRestriction(results)
         val strategy =
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt
index 82e4bc5d77f3f35d217c56a377513c0e7d329170..4ae9ce23b31204b366dce7bcf000e4114d7f3f8f 100644
--- a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt
@@ -21,7 +21,7 @@ import theodolite.util.PatcherDefinition
  */
 @QuarkusTest
 class ResourceLimitPatcherTest {
-    val testPath = "./src/main/resources/testYaml/"
+    val testPath = "./src/test/resources/"
     val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace(""))
     val patcherFactory = PatcherFactory()
 
@@ -31,27 +31,32 @@ class ResourceLimitPatcherTest {
         val k8sResource = loader.loadK8sResource("Deployment", testPath + fileName) as Deployment
 
         val defCPU = PatcherDefinition()
-        defCPU.variableName = "cpu"
         defCPU.resource = "cpu-memory-deployment.yaml"
-        defCPU.container = "uc-application"
         defCPU.type = "ResourceLimitPatcher"
+        defCPU.properties = mutableMapOf(
+            "limitedResource" to "cpu",
+            "container" to "application"
+        )
 
         val defMEM = PatcherDefinition()
-        defMEM.variableName = "memory"
         defMEM.resource = "cpu-memory-deployment.yaml"
-        defMEM.container = "uc-application"
         defMEM.type = "ResourceLimitPatcher"
+        defMEM.properties = mutableMapOf(
+            "limitedResource" to "memory",
+            "container" to "uc-application"
+        )
 
         patcherFactory.createPatcher(
             patcherDefinition = defCPU,
             k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource))
         ).patch(value = cpuValue)
+
         patcherFactory.createPatcher(
             patcherDefinition = defMEM,
             k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource))
         ).patch(value = memValue)
 
-        k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container }
+        k8sResource.spec.template.spec.containers.filter { it.name == defCPU.properties["container"] !! }
             .forEach {
                 assertTrue(it.resources.limits["cpu"].toString() == cpuValue)
                 assertTrue(it.resources.limits["memory"].toString() == memValue)
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt
index 3cd6b012f09c5471b1b011b5cd03e61a0fab1c4e..6f232961871c9d11929fc912a483e6e805cc7daf 100644
--- a/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt
@@ -21,7 +21,7 @@ import theodolite.util.PatcherDefinition
  */
 @QuarkusTest
 class ResourceRequestPatcherTest {
-    val testPath = "./src/main/resources/testYaml/"
+    val testPath = "./src/test/resources/"
     val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace(""))
     val patcherFactory = PatcherFactory()
 
@@ -31,16 +31,20 @@ class ResourceRequestPatcherTest {
         val k8sResource = loader.loadK8sResource("Deployment", testPath + fileName) as Deployment
 
         val defCPU = PatcherDefinition()
-        defCPU.variableName = "cpu"
         defCPU.resource = "cpu-memory-deployment.yaml"
-        defCPU.container = "uc-application"
         defCPU.type = "ResourceRequestPatcher"
+        defCPU.properties = mutableMapOf(
+            "requestedResource" to "cpu",
+            "container" to "application"
+        )
 
         val defMEM = PatcherDefinition()
-        defMEM.variableName = "memory"
         defMEM.resource = "cpu-memory-deployment.yaml"
-        defMEM.container = "uc-application"
         defMEM.type = "ResourceRequestPatcher"
+        defMEM.properties = mutableMapOf(
+            "requestedResource" to "memory",
+            "container" to "application"
+        )
 
         patcherFactory.createPatcher(
             patcherDefinition = defCPU,
@@ -51,7 +55,7 @@ class ResourceRequestPatcherTest {
             k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource))
         ).patch(value = memValue)
 
-        k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container }
+        k8sResource.spec.template.spec.containers.filter { it.name == defCPU.properties["container"] !! }
             .forEach {
                 assertTrue(it.resources.requests["cpu"].toString() == cpuValue)
                 assertTrue(it.resources.requests["memory"].toString() == memValue)
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt
index 71e3cbcc78208cc4227e369d59d841e39adb87ed..6ddca296acced658609fcccb307a83047238e118 100644
--- a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmark.kt
@@ -12,7 +12,8 @@ class TestBenchmark : Benchmark {
         load: LoadDimension,
         res: Resource,
         configurationOverrides: List<ConfigurationOverride?>,
-        loadGenerationDelay: Long
+        loadGenerationDelay: Long,
+        afterTeardownDelay: Long
     ): BenchmarkDeployment {
         return TestBenchmarkDeployment()
     }
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt
index 294727d6a252a29e312ff532937e7fdf9f079ac7..cbd2d5926d61b0bfd4de6fab0c14422ddf88f190 100644
--- a/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt
@@ -14,7 +14,8 @@ class TestBenchmarkExecutorImpl(
     results: Results,
     slo: BenchmarkExecution.Slo,
     executionId: Int,
-    loadGenerationDelay: Long
+    loadGenerationDelay: Long,
+    afterTeardownDelay: Long
 ) :
     BenchmarkExecutor(
         benchmark,
@@ -22,8 +23,10 @@ class TestBenchmarkExecutorImpl(
         executionDuration = Duration.ofSeconds(1),
         configurationOverrides = emptyList(),
         slo = slo,
+        repetitions = 1,
         executionId = executionId,
-        loadGenerationDelay = loadGenerationDelay
+        loadGenerationDelay = loadGenerationDelay,
+        afterTeardownDelay = afterTeardownDelay
     ) {
 
     override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/util/IOHandlerTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/util/IOHandlerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6984c3935da3d26f95565b758547a98e0eeb155f
--- /dev/null
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/util/IOHandlerTest.kt
@@ -0,0 +1,134 @@
+package theodolite.util
+
+import com.google.gson.GsonBuilder
+import io.quarkus.test.junit.QuarkusTest
+import org.hamcrest.CoreMatchers.containsString
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Rule
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+import org.junit.rules.TemporaryFolder
+import org.junitpioneer.jupiter.ClearEnvironmentVariable
+import org.junitpioneer.jupiter.SetEnvironmentVariable
+
+
+const val FOLDER_URL = "Test-Folder"
+@QuarkusTest
+internal class IOHandlerTest {
+
+    @Rule
+    private var temporaryFolder = TemporaryFolder()
+
+    @Test
+    fun testWriteStringToText() {
+        temporaryFolder.create()
+        val testContent = "Test-File-Content"
+        val folder = temporaryFolder.newFolder(FOLDER_URL)
+
+        IOHandler().writeStringToTextFile(
+            fileURL = "${folder.absolutePath}/test-file.txt",
+            data = testContent)
+
+        assertEquals(
+           testContent,
+            IOHandler().readFileAsString("${folder.absolutePath}/test-file.txt")
+        )
+    }
+
+    @Test
+    fun testWriteToCSVFile() {
+        temporaryFolder.create()
+        val folder = temporaryFolder.newFolder(FOLDER_URL)
+
+        val testContent = listOf(
+            listOf("apples","red"),
+            listOf("bananas","yellow"),
+            listOf("avocado","brown"))
+        val columns = listOf("Fruit", "Color")
+
+        IOHandler().writeToCSVFile(
+            fileURL = "${folder.absolutePath}/test-file",
+            data = testContent,
+            columns = columns)
+
+        var expected = "Fruit,Color\n"
+        testContent.forEach { expected += it[0] + "," +  it[1] + "\n" }
+
+        assertEquals(
+            expected.trim(),
+            IOHandler().readFileAsString("${folder.absolutePath}/test-file.csv")
+        )
+    }
+
+    @Test
+    fun testWriteToJSONFile() {
+        temporaryFolder.create()
+        val folder = temporaryFolder.newFolder(FOLDER_URL)
+        val testContent = Resource(0, emptyList())
+
+        IOHandler().writeToJSONFile(
+            fileURL =  "${folder.absolutePath}/test-file.json",
+            objectToSave = testContent)
+
+        val expected = GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create().toJson(testContent)
+
+        assertEquals(
+            expected,
+            IOHandler().readFileAsString("${folder.absolutePath}/test-file.json")
+        )
+    }
+
+    // Test the function `getResultFolderString`
+
+    @Test
+    @ClearEnvironmentVariable.ClearEnvironmentVariables(
+        ClearEnvironmentVariable(key = "RESULTS_FOLDER"),
+        ClearEnvironmentVariable(key = "CREATE_RESULTS_FOLDER")
+    )
+    fun testGetResultFolderURL_emptyEnvironmentVars() {
+        assertEquals("",IOHandler().getResultFolderURL())
+    }
+
+
+    @Test()
+    @SetEnvironmentVariable.SetEnvironmentVariables(
+        SetEnvironmentVariable(key = "RESULTS_FOLDER", value = "./src/test/resources"),
+        SetEnvironmentVariable(key = "CREATE_RESULTS_FOLDER", value = "false")
+    )
+    fun testGetResultFolderURL_FolderExist() {
+        assertEquals("./src/test/resources/", IOHandler().getResultFolderURL())
+    }
+
+    @Test()
+    @SetEnvironmentVariable.SetEnvironmentVariables(
+        SetEnvironmentVariable(key = "RESULTS_FOLDER", value = "$FOLDER_URL-0"),
+        SetEnvironmentVariable(key = "CREATE_RESULTS_FOLDER", value = "false")
+    )
+    fun testGetResultFolderURL_FolderNotExist() {
+        var exceptionWasThrown = false
+        try {
+            IOHandler().getResultFolderURL()
+          } catch (e: Exception){
+              exceptionWasThrown = true
+              assertThat(e.toString(), containsString("Result folder not found"));
+          }
+        assertTrue(exceptionWasThrown)
+    }
+
+    @Test()
+    @SetEnvironmentVariable.SetEnvironmentVariables(
+        SetEnvironmentVariable(key = "RESULTS_FOLDER", value = FOLDER_URL),
+        SetEnvironmentVariable(key = "CREATE_RESULTS_FOLDER", value = "true")
+    )
+    fun testGetResultFolderURL_CreateFolderIfNotExist() {
+        assertEquals("$FOLDER_URL/",  IOHandler().getResultFolderURL())
+    }
+
+    @Test()
+    @ClearEnvironmentVariable(key = "RESULTS_FOLDER" )
+    @SetEnvironmentVariable(key = "CREATE_RESULTS_FOLDER", value = "true")
+    fun testGetResultFolderURL_CreateFolderButNoFolderGiven() {
+        assertEquals("",  IOHandler().getResultFolderURL())
+    }
+}
diff --git a/theodolite-quarkus/src/main/resources/testYaml/cpu-deployment.yaml b/theodolite-quarkus/src/test/resources/cpu-deployment.yaml
similarity index 100%
rename from theodolite-quarkus/src/main/resources/testYaml/cpu-deployment.yaml
rename to theodolite-quarkus/src/test/resources/cpu-deployment.yaml
diff --git a/theodolite-quarkus/src/main/resources/testYaml/cpu-memory-deployment.yaml b/theodolite-quarkus/src/test/resources/cpu-memory-deployment.yaml
similarity index 100%
rename from theodolite-quarkus/src/main/resources/testYaml/cpu-memory-deployment.yaml
rename to theodolite-quarkus/src/test/resources/cpu-memory-deployment.yaml
diff --git a/theodolite-quarkus/src/main/resources/testYaml/memory-deployment.yaml b/theodolite-quarkus/src/test/resources/memory-deployment.yaml
similarity index 100%
rename from theodolite-quarkus/src/main/resources/testYaml/memory-deployment.yaml
rename to theodolite-quarkus/src/test/resources/memory-deployment.yaml
diff --git a/theodolite-quarkus/src/main/resources/testYaml/no-resources-deployment.yaml b/theodolite-quarkus/src/test/resources/no-resources-deployment.yaml
similarity index 100%
rename from theodolite-quarkus/src/main/resources/testYaml/no-resources-deployment.yaml
rename to theodolite-quarkus/src/test/resources/no-resources-deployment.yaml