diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000000000000000000000000000000000000..b1c7ffdbcd7523245c451869092ff0498bd7b8db --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +www.theodolite.rocks \ No newline at end of file diff --git a/docs/crd-benchmark-doc.md b/docs/crd-benchmark-doc.md deleted file mode 100644 index 1e12d6ebd776b11d76241cfb530daeba9e0b5c24..0000000000000000000000000000000000000000 --- a/docs/crd-benchmark-doc.md +++ /dev/null @@ -1,374 +0,0 @@ -# API Reference - -Packages: - -- [theodolite.com/v1](#theodolitecomv1) - -# theodolite.com/v1 - -Resource Types: - -- [benchmark](#benchmark) - - - - -## benchmark -<sup><sup>[↩ Parent](#theodolitecomv1 )</sup></sup> - - - - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>apiVersion</b></td> - <td>string</td> - <td>theodolite.com/v1</td> - <td>true</td> - </tr> - <tr> - <td><b>kind</b></td> - <td>string</td> - <td>benchmark</td> - <td>true</td> - </tr> - <tr> - <td><b><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#objectmeta-v1-meta">metadata</a></b></td> - <td>object</td> - <td>Refer to the Kubernetes API documentation for the fields of the `metadata` field.</td> - <td>true</td> - </tr><tr> - <td><b><a href="#benchmarkspec">spec</a></b></td> - <td>object</td> - <td> - <br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### benchmark.spec -<sup><sup>[↩ Parent](#benchmark)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>name</b></td> - <td>string</td> - <td> - This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten.<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>appResource</b></td> - <td>[]string</td> - <td> - A list of file names that reference Kubernetes resources that are deployed on the cluster for the system under test (SUT).<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#benchmarkspeckafkaconfig">kafkaConfig</a></b></td> - <td>object</td> - <td> - Contains the Kafka configuration.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>loadGenResource</b></td> - <td>[]string</td> - <td> - A list of file names that reference Kubernetes resources that are deployed on the cluster for the load generator.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#benchmarkspecloadtypesindex">loadTypes</a></b></td> - <td>[]object</td> - <td> - 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.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#benchmarkspecresourcetypesindex">resourceTypes</a></b></td> - <td>[]object</td> - <td> - A list of resource types that can be scaled for this `benchmark` resource. For each resource type the concrete values are defined in the `execution` object.<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### benchmark.spec.kafkaConfig -<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> - - - -Contains the Kafka configuration. - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>bootstrapServer</b></td> - <td>string</td> - <td> - The bootstrap servers connection string.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#benchmarkspeckafkaconfigtopicsindex">topics</a></b></td> - <td>[]object</td> - <td> - List of topics to be created for each experiment. Alternative theodolite offers the possibility to remove certain topics after each experiment.<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### benchmark.spec.kafkaConfig.topics[index] -<sup><sup>[↩ Parent](#benchmarkspeckafkaconfig)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>removeOnly</b></td> - <td>boolean</td> - <td> - Determines if this topic should only be deleted after each experiement. For removeOnly topics the name can be a RegEx describing the topic.<br/> - <br/> - <i>Default</i>: false<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>name</b></td> - <td>string</td> - <td> - The name of the topic.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>true</td> - </tr><tr> - <td><b>numPartitions</b></td> - <td>integer</td> - <td> - The number of partitions of the topic.<br/> - <br/> - <i>Default</i>: 0<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>replicationFactor</b></td> - <td>integer</td> - <td> - The replication factor of the topic.<br/> - <br/> - <i>Default</i>: 0<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### benchmark.spec.loadTypes[index] -<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b><a href="#benchmarkspecloadtypesindexpatchersindex">patchers</a></b></td> - <td>[]object</td> - <td> - List of patchers used to scale this resource type.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>typeName</b></td> - <td>string</td> - <td> - Name of the load type.<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### benchmark.spec.loadTypes[index].patchers[index] -<sup><sup>[↩ Parent](#benchmarkspecloadtypesindex)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>properties</b></td> - <td>object</td> - <td> - (Optional) Patcher specific additional arguments.<br/> - <br/> - <i>Default</i>: map[]<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>resource</b></td> - <td>string</td> - <td> - Specifies the Kubernetes resource to be patched.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>true</td> - </tr><tr> - <td><b>type</b></td> - <td>string</td> - <td> - Type of the Patcher.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### benchmark.spec.resourceTypes[index] -<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b><a href="#benchmarkspecresourcetypesindexpatchersindex">patchers</a></b></td> - <td>[]object</td> - <td> - List of patchers used to scale this resource type.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>typeName</b></td> - <td>string</td> - <td> - Name of the resource type.<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### benchmark.spec.resourceTypes[index].patchers[index] -<sup><sup>[↩ Parent](#benchmarkspecresourcetypesindex)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>properties</b></td> - <td>object</td> - <td> - (Optional) Patcher specific additional arguments.<br/> - <br/> - <i>Default</i>: map[]<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>resource</b></td> - <td>string</td> - <td> - Specifies the Kubernetes resource to be patched.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>true</td> - </tr><tr> - <td><b>type</b></td> - <td>string</td> - <td> - Type of the patcher.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>true</td> - </tr></tbody> -</table> \ No newline at end of file diff --git a/docs/crd-docu.md b/docs/crd-docu.md new file mode 100644 index 0000000000000000000000000000000000000000..73d85c951fc2958aee25cde2cdff652034643c1a --- /dev/null +++ b/docs/crd-docu.md @@ -0,0 +1,1226 @@ +# API Reference + +Packages: + +- [theodolite.com/v1](#theodolitecomv1) + +# theodolite.com/v1 + +Resource Types: + +- [benchmark](#benchmark) + +- [execution](#execution) + + + + +## benchmark +<sup><sup>[↩ Parent](#theodolitecomv1 )</sup></sup> + + + + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>apiVersion</b></td> + <td>string</td> + <td>theodolite.com/v1</td> + <td>true</td> + </tr> + <tr> + <td><b>kind</b></td> + <td>string</td> + <td>benchmark</td> + <td>true</td> + </tr> + <tr> + <td><b><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#objectmeta-v1-meta">metadata</a></b></td> + <td>object</td> + <td>Refer to the Kubernetes API documentation for the fields of the `metadata` field.</td> + <td>true</td> + </tr><tr> + <td><b><a href="#benchmarkstatus">status</a></b></td> + <td>object</td> + <td> + <br/> + </td> + <td>false</td> + </tr><tr> + <td><b><a href="#benchmarkspec">spec</a></b></td> + <td>object</td> + <td> + <br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.status +<sup><sup>[↩ Parent](#benchmark)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>resourceSetsState</b></td> + <td>string</td> + <td> + The status of a Benchmark indicates whether all resources are available to start the benchmark or not.<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec +<sup><sup>[↩ Parent](#benchmark)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecinfrastructure">infrastructure</a></b></td> + <td>object</td> + <td> + (Optional) A list of file names that reference Kubernetes resources that are deployed on the cluster to create the required infrastructure.<br/> + <br/> + <i>Default</i>: map[]<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>name</b></td> + <td>string</td> + <td> + This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>false</td> + </tr><tr> + <td><b><a href="#benchmarkspeckafkaconfig">kafkaConfig</a></b></td> + <td>object</td> + <td> + Contains the Kafka configuration.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#benchmarkspecloadgenerator">loadGenerator</a></b></td> + <td>object</td> + <td> + The loadGenResourceSets specifies all Kubernetes resources required to start the load generator. A resourceSet can be either a configMap resourceSet or a fileSystem resourceSet.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#benchmarkspecloadtypesindex">loadTypes</a></b></td> + <td>[]object</td> + <td> + 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.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#benchmarkspecresourcetypesindex">resourceTypes</a></b></td> + <td>[]object</td> + <td> + A list of resource types that can be scaled for this `benchmark` resource. For each resource type the concrete values are defined in the `execution` object.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#benchmarkspecsut">sut</a></b></td> + <td>object</td> + <td> + The appResourceSets specifies all Kubernetes resources required to start the sut. A resourceSet can be either a configMap resourceSet or a fileSystem resourceSet.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.spec.infrastructure +<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> + + + +(Optional) A list of file names that reference Kubernetes resources that are deployed on the cluster to create the required infrastructure. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecinfrastructureresourcesindex">resources</a></b></td> + <td>[]object</td> + <td> + <br/> + <br/> + <i>Default</i>: []<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.infrastructure.resources[index] +<sup><sup>[↩ Parent](#benchmarkspecinfrastructure)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecinfrastructureresourcesindexconfigmap">configMap</a></b></td> + <td>object</td> + <td> + The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b><a href="#benchmarkspecinfrastructureresourcesindexfilesystem">fileSystem</a></b></td> + <td>object</td> + <td> + The fileSystem resourceSet loads the Kubernetes manifests from the filesystem.<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.infrastructure.resources[index].configMap +<sup><sup>[↩ Parent](#benchmarkspecinfrastructureresourcesindex)</sup></sup> + + + +The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>files</b></td> + <td>[]string</td> + <td> + (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>name</b></td> + <td>string</td> + <td> + The name of the configMap<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.infrastructure.resources[index].fileSystem +<sup><sup>[↩ Parent](#benchmarkspecinfrastructureresourcesindex)</sup></sup> + + + +The fileSystem resourceSet loads the Kubernetes manifests from the filesystem. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>files</b></td> + <td>[]string</td> + <td> + (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>path</b></td> + <td>string</td> + <td> + The path to the folder which contains the Kubernetes manifests files.<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.kafkaConfig +<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> + + + +Contains the Kafka configuration. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>bootstrapServer</b></td> + <td>string</td> + <td> + The bootstrap servers connection string.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#benchmarkspeckafkaconfigtopicsindex">topics</a></b></td> + <td>[]object</td> + <td> + List of topics to be created for each experiment. Alternative theodolite offers the possibility to remove certain topics after each experiment.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.spec.kafkaConfig.topics[index] +<sup><sup>[↩ Parent](#benchmarkspeckafkaconfig)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>numPartitions</b></td> + <td>integer</td> + <td> + The number of partitions of the topic.<br/> + <br/> + <i>Default</i>: 0<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>removeOnly</b></td> + <td>boolean</td> + <td> + Determines if this topic should only be deleted after each experiement. For removeOnly topics the name can be a RegEx describing the topic.<br/> + <br/> + <i>Default</i>: false<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>replicationFactor</b></td> + <td>integer</td> + <td> + The replication factor of the topic.<br/> + <br/> + <i>Default</i>: 0<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>name</b></td> + <td>string</td> + <td> + The name of the topic.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.spec.loadGenerator +<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> + + + +The loadGenResourceSets specifies all Kubernetes resources required to start the load generator. A resourceSet can be either a configMap resourceSet or a fileSystem resourceSet. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecloadgeneratorresourcesindex">resources</a></b></td> + <td>[]object</td> + <td> + <br/> + <br/> + <i>Default</i>: []<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.loadGenerator.resources[index] +<sup><sup>[↩ Parent](#benchmarkspecloadgenerator)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecloadgeneratorresourcesindexconfigmap">configMap</a></b></td> + <td>object</td> + <td> + The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b><a href="#benchmarkspecloadgeneratorresourcesindexfilesystem">fileSystem</a></b></td> + <td>object</td> + <td> + The fileSystem resourceSet loads the Kubernetes manifests from the filesystem.<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.loadGenerator.resources[index].configMap +<sup><sup>[↩ Parent](#benchmarkspecloadgeneratorresourcesindex)</sup></sup> + + + +The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>files</b></td> + <td>[]string</td> + <td> + (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>name</b></td> + <td>string</td> + <td> + The name of the configMap<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.loadGenerator.resources[index].fileSystem +<sup><sup>[↩ Parent](#benchmarkspecloadgeneratorresourcesindex)</sup></sup> + + + +The fileSystem resourceSet loads the Kubernetes manifests from the filesystem. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>files</b></td> + <td>[]string</td> + <td> + (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>path</b></td> + <td>string</td> + <td> + The path to the folder which contains the Kubernetes manifests files.<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.loadTypes[index] +<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecloadtypesindexpatchersindex">patchers</a></b></td> + <td>[]object</td> + <td> + List of patchers used to scale this resource type.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>typeName</b></td> + <td>string</td> + <td> + Name of the load type.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.spec.loadTypes[index].patchers[index] +<sup><sup>[↩ Parent](#benchmarkspecloadtypesindex)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>properties</b></td> + <td>map[string]string</td> + <td> + (Optional) Patcher specific additional arguments.<br/> + <br/> + <i>Default</i>: map[]<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>resource</b></td> + <td>string</td> + <td> + Specifies the Kubernetes resource to be patched.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>true</td> + </tr><tr> + <td><b>type</b></td> + <td>string</td> + <td> + Type of the Patcher.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.spec.resourceTypes[index] +<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecresourcetypesindexpatchersindex">patchers</a></b></td> + <td>[]object</td> + <td> + List of patchers used to scale this resource type.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>typeName</b></td> + <td>string</td> + <td> + Name of the resource type.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.spec.resourceTypes[index].patchers[index] +<sup><sup>[↩ Parent](#benchmarkspecresourcetypesindex)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>properties</b></td> + <td>map[string]string</td> + <td> + (Optional) Patcher specific additional arguments.<br/> + <br/> + <i>Default</i>: map[]<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>resource</b></td> + <td>string</td> + <td> + Specifies the Kubernetes resource to be patched.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>true</td> + </tr><tr> + <td><b>type</b></td> + <td>string</td> + <td> + Type of the patcher.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### benchmark.spec.sut +<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup> + + + +The appResourceSets specifies all Kubernetes resources required to start the sut. A resourceSet can be either a configMap resourceSet or a fileSystem resourceSet. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecsutresourcesindex">resources</a></b></td> + <td>[]object</td> + <td> + <br/> + <br/> + <i>Default</i>: []<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.sut.resources[index] +<sup><sup>[↩ Parent](#benchmarkspecsut)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#benchmarkspecsutresourcesindexconfigmap">configMap</a></b></td> + <td>object</td> + <td> + The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b><a href="#benchmarkspecsutresourcesindexfilesystem">fileSystem</a></b></td> + <td>object</td> + <td> + The fileSystem resourceSet loads the Kubernetes manifests from the filesystem.<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.sut.resources[index].configMap +<sup><sup>[↩ Parent](#benchmarkspecsutresourcesindex)</sup></sup> + + + +The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>files</b></td> + <td>[]string</td> + <td> + (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>name</b></td> + <td>string</td> + <td> + The name of the configMap<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### benchmark.spec.sut.resources[index].fileSystem +<sup><sup>[↩ Parent](#benchmarkspecsutresourcesindex)</sup></sup> + + + +The fileSystem resourceSet loads the Kubernetes manifests from the filesystem. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>files</b></td> + <td>[]string</td> + <td> + (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>path</b></td> + <td>string</td> + <td> + The path to the folder which contains the Kubernetes manifests files.<br/> + </td> + <td>false</td> + </tr></tbody> +</table> + +## execution +<sup><sup>[↩ Parent](#theodolitecomv1 )</sup></sup> + + + + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>apiVersion</b></td> + <td>string</td> + <td>theodolite.com/v1</td> + <td>true</td> + </tr> + <tr> + <td><b>kind</b></td> + <td>string</td> + <td>execution</td> + <td>true</td> + </tr> + <tr> + <td><b><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#objectmeta-v1-meta">metadata</a></b></td> + <td>object</td> + <td>Refer to the Kubernetes API documentation for the fields of the `metadata` field.</td> + <td>true</td> + </tr><tr> + <td><b><a href="#executionstatus">status</a></b></td> + <td>object</td> + <td> + <br/> + </td> + <td>false</td> + </tr><tr> + <td><b><a href="#executionspec">spec</a></b></td> + <td>object</td> + <td> + <br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### execution.status +<sup><sup>[↩ Parent](#execution)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>executionDuration</b></td> + <td>string</td> + <td> + Duration of the execution in seconds<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>executionState</b></td> + <td>string</td> + <td> + <br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### execution.spec +<sup><sup>[↩ Parent](#execution)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>name</b></td> + <td>string</td> + <td> + This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>false</td> + </tr><tr> + <td><b>benchmark</b></td> + <td>string</td> + <td> + The name of the benchmark this execution is referring to.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#executionspecconfigoverridesindex">configOverrides</a></b></td> + <td>[]object</td> + <td> + List of patchers that are used to override existing configurations.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#executionspecexecution">execution</a></b></td> + <td>object</td> + <td> + Defines the overall parameter for the execution.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#executionspecload">load</a></b></td> + <td>object</td> + <td> + Specifies the load values that are benchmarked.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#executionspecresources">resources</a></b></td> + <td>object</td> + <td> + Specifies the scaling resource that is benchmarked.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b><a href="#executionspecslosindex">slos</a></b></td> + <td>[]object</td> + <td> + List of resource values for the specified resource type.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### execution.spec.configOverrides[index] +<sup><sup>[↩ Parent](#executionspec)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b><a href="#executionspecconfigoverridesindexpatcher">patcher</a></b></td> + <td>object</td> + <td> + Patcher used to patch a resource<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>value</b></td> + <td>string</td> + <td> + <br/> + </td> + <td>false</td> + </tr></tbody> +</table> + + +### execution.spec.configOverrides[index].patcher +<sup><sup>[↩ Parent](#executionspecconfigoverridesindex)</sup></sup> + + + +Patcher used to patch a resource + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>properties</b></td> + <td>map[string]string</td> + <td> + (Optional) Patcher specific additional arguments.<br/> + <br/> + <i>Default</i>: map[]<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>resource</b></td> + <td>string</td> + <td> + Specifies the Kubernetes resource to be patched.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>true</td> + </tr><tr> + <td><b>type</b></td> + <td>string</td> + <td> + Type of the Patcher.<br/> + <br/> + <i>Default</i>: <br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### execution.spec.execution +<sup><sup>[↩ Parent](#executionspec)</sup></sup> + + + +Defines the overall parameter for the execution. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>loadGenerationDelay</b></td> + <td>integer</td> + <td> + Seconds to wait between the start of the SUT and the load generator.<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>duration</b></td> + <td>integer</td> + <td> + Defines the duration of each experiment in seconds.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>repetitions</b></td> + <td>integer</td> + <td> + Numper of repititions for each experiments.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>restrictions</b></td> + <td>[]string</td> + <td> + List of restriction strategys used to delimit the search space.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>strategy</b></td> + <td>string</td> + <td> + Defines the used strategy for the execution, either 'LinearSearch' or 'BinarySearch'<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### execution.spec.load +<sup><sup>[↩ Parent](#executionspec)</sup></sup> + + + +Specifies the load values that are benchmarked. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>loadType</b></td> + <td>string</td> + <td> + The type of the load. It must match one of the load types specified in the referenced benchmark.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>loadValues</b></td> + <td>[]integer</td> + <td> + List of load values for the specified load type.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### execution.spec.resources +<sup><sup>[↩ Parent](#executionspec)</sup></sup> + + + +Specifies the scaling resource that is benchmarked. + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>resourceType</b></td> + <td>string</td> + <td> + The type of the resource. It must match one of the resource types specified in the referenced benchmark.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>resourceValues</b></td> + <td>[]integer</td> + <td> + List of resource values for the specified resource type.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> + + +### execution.spec.slos[index] +<sup><sup>[↩ Parent](#executionspec)</sup></sup> + + + + + +<table> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Description</th> + <th>Required</th> + </tr> + </thead> + <tbody><tr> + <td><b>properties</b></td> + <td>map[string]string</td> + <td> + (Optional) SLO specific additional arguments.<br/> + <br/> + <i>Default</i>: map[]<br/> + </td> + <td>false</td> + </tr><tr> + <td><b>offset</b></td> + <td>integer</td> + <td> + Hours by which the start and end timestamp will be shifted (for different timezones).<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>prometheusUrl</b></td> + <td>string</td> + <td> + Connection string for Promehteus.<br/> + </td> + <td>true</td> + </tr><tr> + <td><b>sloType</b></td> + <td>string</td> + <td> + The type of the SLO. It must match 'lag trend'.<br/> + </td> + <td>true</td> + </tr></tbody> +</table> \ No newline at end of file diff --git a/docs/crd-execution-doc.md b/docs/crd-execution-doc.md deleted file mode 100644 index 21b5cdecabd4a247df9f2c0c8d376ad578f4032f..0000000000000000000000000000000000000000 --- a/docs/crd-execution-doc.md +++ /dev/null @@ -1,438 +0,0 @@ -# API Reference - -Packages: - -- [theodolite.com/v1](#theodolitecomv1) - -# theodolite.com/v1 - -Resource Types: - -- [execution](#execution) - - - - -## execution -<sup><sup>[↩ Parent](#theodolitecomv1 )</sup></sup> - - - - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>apiVersion</b></td> - <td>string</td> - <td>theodolite.com/v1</td> - <td>true</td> - </tr> - <tr> - <td><b>kind</b></td> - <td>string</td> - <td>execution</td> - <td>true</td> - </tr> - <tr> - <td><b><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#objectmeta-v1-meta">metadata</a></b></td> - <td>object</td> - <td>Refer to the Kubernetes API documentation for the fields of the `metadata` field.</td> - <td>true</td> - </tr><tr> - <td><b><a href="#executionstatus">status</a></b></td> - <td>object</td> - <td> - <br/> - </td> - <td>false</td> - </tr><tr> - <td><b><a href="#executionspec">spec</a></b></td> - <td>object</td> - <td> - <br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### execution.status -<sup><sup>[↩ Parent](#execution)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>executionDuration</b></td> - <td>string</td> - <td> - Duration of the execution in seconds<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>executionState</b></td> - <td>string</td> - <td> - <br/> - </td> - <td>false</td> - </tr></tbody> -</table> - - -### execution.spec -<sup><sup>[↩ Parent](#execution)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>name</b></td> - <td>string</td> - <td> - This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>false</td> - </tr><tr> - <td><b>benchmark</b></td> - <td>string</td> - <td> - The name of the benchmark this execution is referring to.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#executionspecconfigoverridesindex">configOverrides</a></b></td> - <td>[]object</td> - <td> - List of patchers that are used to override existing configurations.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#executionspecexecution">execution</a></b></td> - <td>object</td> - <td> - Defines the overall parameter for the execution.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#executionspecload">load</a></b></td> - <td>object</td> - <td> - Specifies the load values that are benchmarked.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#executionspecresources">resources</a></b></td> - <td>object</td> - <td> - Specifies the scaling resource that is benchmarked.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b><a href="#executionspecslosindex">slos</a></b></td> - <td>[]object</td> - <td> - List of resource values for the specified resource type.<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### execution.spec.configOverrides[index] -<sup><sup>[↩ Parent](#executionspec)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b><a href="#executionspecconfigoverridesindexpatcher">patcher</a></b></td> - <td>object</td> - <td> - Patcher used to patch a resource<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>value</b></td> - <td>string</td> - <td> - <br/> - </td> - <td>false</td> - </tr></tbody> -</table> - - -### execution.spec.configOverrides[index].patcher -<sup><sup>[↩ Parent](#executionspecconfigoverridesindex)</sup></sup> - - - -Patcher used to patch a resource - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>properties</b></td> - <td>object</td> - <td> - (Optional) Patcher specific additional arguments.<br/> - <br/> - <i>Default</i>: map[]<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>resource</b></td> - <td>string</td> - <td> - Specifies the Kubernetes resource to be patched.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>true</td> - </tr><tr> - <td><b>type</b></td> - <td>string</td> - <td> - Type of the Patcher.<br/> - <br/> - <i>Default</i>: <br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### execution.spec.execution -<sup><sup>[↩ Parent](#executionspec)</sup></sup> - - - -Defines the overall parameter for the execution. - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>loadGenerationDelay</b></td> - <td>integer</td> - <td> - Seconds to wait between the start of the SUT and the load generator.<br/> - </td> - <td>false</td> - </tr><tr> - <td><b>duration</b></td> - <td>integer</td> - <td> - Defines the duration of each experiment in seconds.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>repetitions</b></td> - <td>integer</td> - <td> - Numper of repititions for each experiments.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>restrictions</b></td> - <td>[]string</td> - <td> - List of restriction strategys used to delimit the search space.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>strategy</b></td> - <td>string</td> - <td> - Defines the used strategy for the execution, either 'LinearSearch' or 'BinarySearch'<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### execution.spec.load -<sup><sup>[↩ Parent](#executionspec)</sup></sup> - - - -Specifies the load values that are benchmarked. - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>loadType</b></td> - <td>string</td> - <td> - The type of the load. It must match one of the load types specified in the referenced benchmark.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>loadValues</b></td> - <td>[]integer</td> - <td> - List of load values for the specified load type.<br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### execution.spec.resources -<sup><sup>[↩ Parent](#executionspec)</sup></sup> - - - -Specifies the scaling resource that is benchmarked. - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>resourceType</b></td> - <td>string</td> - <td> - The type of the resource. It must match one of the resource types specified in the referenced benchmark.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>resourceValues</b></td> - <td>[]integer</td> - <td> - <br/> - </td> - <td>true</td> - </tr></tbody> -</table> - - -### execution.spec.slos[index] -<sup><sup>[↩ Parent](#executionspec)</sup></sup> - - - - - -<table> - <thead> - <tr> - <th>Name</th> - <th>Type</th> - <th>Description</th> - <th>Required</th> - </tr> - </thead> - <tbody><tr> - <td><b>externalSloUrl</b></td> - <td>string</td> - <td> - Connection string for a external slo analysis.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>offset</b></td> - <td>integer</td> - <td> - Hours by which the start and end timestamp will be shifted (for different timezones).<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>prometheusUrl</b></td> - <td>string</td> - <td> - Connection string for Promehteus.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>sloType</b></td> - <td>string</td> - <td> - The type of the SLO. It must match 'lag trend'.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>threshold</b></td> - <td>integer</td> - <td> - The threshold the SUT should meet for a sucessful experiment.<br/> - </td> - <td>true</td> - </tr><tr> - <td><b>warmup</b></td> - <td>integer</td> - <td> - Seconds of time that are ignored in the analysis.<br/> - </td> - <td>true</td> - </tr></tbody> -</table> \ No newline at end of file diff --git a/execution/README.md b/execution/README.md index eb6ade9f2aab28b6d237e9622f22da0ea5998a50..c12eff782ffc129bb4b1820ce4a1e3076ab4f8ad 100644 --- a/execution/README.md +++ b/execution/README.md @@ -1,13 +1,13 @@ # Theodolite Execution Framework +**Please note: Most of the content in this directory is deprecated. Please refer to the `helm` directory for installing the latest version of Theodolite.** + This directory contains the Theodolite framework for executing scalability benchmarks in a Kubernetes cluster. As Theodolite aims for executing benchmarks in realistic execution environments, some third-party components are [required](#installation). After everything is installed and configured, you can move on the [execution of benchmarks](#execution). -*Note: The currently released version of Theodolite only allows running Kafka Streams benchmarks. With the upcoming release `0.5`, we plan to support arbitrary stream processing engines, in particular, our already available implementations for Apache Flink. To already run them now, please contact us.* - ## Installation For executing benchmarks, access to a Kubernetes cluster is required. If you already run other applications inside your diff --git a/helm/README.md b/helm/README.md index 1a3428b5e601de0c6c33f9dab236321e95592c6c..af253482bcbacf628fd718eb70b3b157cc06e3f8 100644 --- a/helm/README.md +++ b/helm/README.md @@ -9,6 +9,8 @@ helm dependencies update . helm install theodolite . ``` +**Hint for Windows users:** The Theodolite Helm chart makes use of some symbolic links. These are not properly created when this repository is checked out with Windows. There are a couple of solutions presented in this [Stack Overflow post](https://stackoverflow.com/q/5917249/4121056). A simpler workaround is to manually delete the symbolic links and replace them by the files and folders, they are pointing to. The relevant symbolic links are `benchmark-definitions` and the files inside `crd`. + ## Customize Installation As usual, the installation with Helm can be configured by passing a values YAML file: diff --git a/helm/preconfigs/oci.yaml b/helm/preconfigs/oci.yaml index dd070a1d7983404add85cf75ded0a057a76e854f..35fe5dcf423eed77cb2d3d4298088738125fa9fe 100644 --- a/helm/preconfigs/oci.yaml +++ b/helm/preconfigs/oci.yaml @@ -1,4 +1,6 @@ operator: resultsVolume: - storageClassName: "oci-bv" - size: 50Gi # minimal size in OCI \ No newline at end of file + persistent: + enabled: true + storageClassName: "oci-bv" + size: 50Gi # minimal size in OCI diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index b530b553ea90671aba8154cc250a20924bae0183..569cf454a950f3f621c23472f0346c8bbd52229d 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -65,5 +65,5 @@ Create the name of the service account to use Create the name of the results volume to use */}} {{- define "theodolite.resultsClaimName" -}} -{{- default (printf "%s-results" (include "theodolite.fullname" .)) .Values.operator.resultsVolume.existingClaim }} +{{- default (printf "%s-results" (include "theodolite.fullname" .)) .Values.operator.resultsVolume.persistent.existingClaim }} {{- end }} diff --git a/helm/templates/theodolite/benchmark-resources-config-map.yaml b/helm/templates/theodolite/benchmark-resources-config-map.yaml deleted file mode 100644 index 4ec1c1bd9c3b9c05cb77920c20b9b573d413c94a..0000000000000000000000000000000000000000 --- a/helm/templates/theodolite/benchmark-resources-config-map.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- $processedDict := dict -}} -{{- range $path, $bytes := .Files.Glob "benchmark-definitions/**/resources/**" }} -{{- $name := base (dir (dir $path)) }} -{{- if not (hasKey $processedDict $name) -}} -{{ $_ := set $processedDict $name "true" }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: benchmark-resources-{{ $name }} -data: -{{ ($.Files.Glob (printf "benchmark-definitions/%s/resources/*" $name)).AsConfig | indent 2 }} ---- -{{- end }} -{{- end }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: benchmark-resources-custom -data: {} diff --git a/helm/templates/theodolite/benchmarks/benchmark-resources-config-map.yaml b/helm/templates/theodolite/benchmarks/benchmark-resources-config-map.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2dd355141350921d772edb73a1e8e7795600b0d1 --- /dev/null +++ b/helm/templates/theodolite/benchmarks/benchmark-resources-config-map.yaml @@ -0,0 +1,12 @@ +{{- range $configmap, $enabled := .Values.operator.theodoliteBenchmarks.resourceConfigMaps }} +{{- if $enabled -}} +{{- $name := kebabcase $configmap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: benchmark-resources-{{ $name }} +data: +{{ ($.Files.Glob (printf "benchmark-definitions/%s/resources/*" $name)).AsConfig | indent 2 }} +--- +{{- end }} +{{- end }} diff --git a/helm/templates/theodolite/benchmarks/benchmark.yaml b/helm/templates/theodolite/benchmarks/benchmark.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1c4cb02ea69dbed711b781535127e00e2a24f1d7 --- /dev/null +++ b/helm/templates/theodolite/benchmarks/benchmark.yaml @@ -0,0 +1,7 @@ +{{- range $benchmark, $enabled := .Values.operator.theodoliteBenchmarks.benchmarks }} +{{- if $enabled -}} +{{- $name := kebabcase $benchmark }} +{{ $.Files.Get (printf "benchmark-definitions/%s/%s-benchmark-operator.yaml" $name $name) }} +--- +{{- end }} +{{- end }} diff --git a/helm/templates/theodolite/random-scheduler/deployment.yaml b/helm/templates/theodolite/random-scheduler/deployment.yaml index 55b6e4ad5f8fafccc9623e69ef1df1fccf81ed39..132c5dcf86b9bf6213ac0db6cc03fb1dbadbc2cd 100644 --- a/helm/templates/theodolite/random-scheduler/deployment.yaml +++ b/helm/templates/theodolite/random-scheduler/deployment.yaml @@ -27,4 +27,8 @@ spec: env: - name: TARGET_NAMESPACE value: {{ .Release.Namespace }} + {{- with .Values.randomScheduler.nodeSelector }} + nodeSelector: + {{ toYaml . | indent 2 }} + {{- end }} {{- end }} diff --git a/helm/templates/theodolite/results-volume/pvc.yaml b/helm/templates/theodolite/results-volume/pvc.yaml index 6dda16bc85d308c8bf0c9c41dd55cca3582f0793..26ac56e42889ccaebbc669791ad4d318b8318fec 100644 --- a/helm/templates/theodolite/results-volume/pvc.yaml +++ b/helm/templates/theodolite/results-volume/pvc.yaml @@ -1,18 +1,18 @@ -{{- if and .Values.operator.resultsVolume.enabled (not .Values.operator.resultsVolume.existingClaim) -}} +{{- if and .Values.operator.resultsVolume.persistent.enabled (not .Values.operator.resultsVolume.persistent.existingClaim) -}} apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ include "theodolite.resultsClaimName" . }} spec: - {{- if .Values.operator.resultsVolume.storageClassName }} - storageClassName: {{ .Values.operator.resultsVolume.storageClassName }} + {{- if .Values.operator.resultsVolume.persistent.storageClassName }} + storageClassName: {{ .Values.operator.resultsVolume.persistent.storageClassName }} {{- end }} accessModes: - ReadWriteOnce - {{- range .Values.operator.resultsVolume.accessModes }} + {{- range .Values.operator.resultsVolume.persistent.accessModes }} - {{ . | quote }} {{- end }} resources: requests: - storage: {{ .Values.operator.resultsVolume.size | quote }} + storage: {{ .Values.operator.resultsVolume.persistent.size | quote }} {{- end }} \ No newline at end of file diff --git a/helm/templates/theodolite/role.yaml b/helm/templates/theodolite/role.yaml index b9924ea4908718c361851ff6137b44a19589a0be..43ee0e43d6974cd95548df32d6c4b1df8f3e497e 100644 --- a/helm/templates/theodolite/role.yaml +++ b/helm/templates/theodolite/role.yaml @@ -49,6 +49,7 @@ rules: - theodolite.com resources: - benchmarks + - benchmarks/status - executions - executions/status verbs: @@ -68,5 +69,11 @@ rules: - get - create - update + - apiGroups: + - "" + resources: + - events + verbs: + - create {{- end }} {{- end }} \ No newline at end of file diff --git a/helm/templates/theodolite/theodolite-operator.yaml b/helm/templates/theodolite/theodolite-operator.yaml index 52ddcd500ab8d050187028026def84e9d057c252..c7ced880cbbfbb9795ef59156ea1df7d5b860ec6 100644 --- a/helm/templates/theodolite/theodolite-operator.yaml +++ b/helm/templates/theodolite/theodolite-operator.yaml @@ -26,33 +26,11 @@ spec: value: {{ .Release.Namespace }} - name: MODE value: operator - - name: THEODOLITE_APP_RESOURCES - value: "./benchmark-resources" - name: RESULTS_FOLDER value: "./results" volumeMounts: - {{- if .Values.operator.resultsVolume.enabled }} - - name: theodolite-pv-storage + - name: theodolite-results-volume mountPath: "/deployments/results" - {{- end }} - - name: benchmark-resources-uc1-kstreams - mountPath: /deployments/benchmark-resources/uc1-kstreams - - name: benchmark-resources-uc2-kstreams - mountPath: /deployments/benchmark-resources/uc2-kstreams - - name: benchmark-resources-uc3-kstreams - mountPath: /deployments/benchmark-resources/uc3-kstreams - - name: benchmark-resources-uc4-kstreams - mountPath: /deployments/benchmark-resources/uc4-kstreams - - name: benchmark-resources-uc1-flink - mountPath: /deployments/benchmark-resources/uc1-flink - - name: benchmark-resources-uc2-flink - mountPath: /deployments/benchmark-resources/uc2-flink - - name: benchmark-resources-uc3-flink - mountPath: /deployments/benchmark-resources/uc3-flink - - name: benchmark-resources-uc4-flink - mountPath: /deployments/benchmark-resources/uc4-flink - - name: benchmark-resources-custom - mountPath: /deployments/benchmark-resources/custom {{- if .Values.operator.sloChecker.lagTrend.enabled }} - name: lag-trend-slo-checker image: "{{ .Values.operator.sloChecker.lagTrend.image }}:{{ .Values.operator.sloChecker.lagTrend.imageTag }}" @@ -77,7 +55,7 @@ spec: - name: LOG_LEVEL value: INFO {{- end }} - {{- if and .Values.operator.resultsVolume.enabled .Values.operator.resultsVolume.accessSidecar.enabled }} + {{- if .Values.operator.resultsVolume.accessSidecar.enabled }} - name: results-access image: busybox:stable image: "{{ .Values.operator.resultsVolume.accessSidecar.image }}:{{ .Values.operator.resultsVolume.accessSidecar.imageTag }}" @@ -88,48 +66,18 @@ spec: - exec tail -f /dev/null volumeMounts: - mountPath: /results - name: theodolite-pv-storage + name: theodolite-results-volume {{- end }} volumes: - {{- if .Values.operator.resultsVolume.enabled }} - - name: theodolite-pv-storage + - name: theodolite-results-volume + {{- if .Values.operator.resultsVolume.persistent.enabled }} persistentVolumeClaim: claimName: {{ include "theodolite.resultsClaimName" . | quote }} + {{- else }} + emptyDir: {} + {{- end }} + {{- with .Values.operator.nodeSelector }} + nodeSelector: + {{ toYaml . | indent 2 }} {{- end }} - - name: benchmark-resources-uc1-kstreams - configMap: - name: benchmark-resources-uc1-kstreams - optional: true - - name: benchmark-resources-uc2-kstreams - configMap: - name: benchmark-resources-uc2-kstreams - optional: true - - name: benchmark-resources-uc3-kstreams - configMap: - name: benchmark-resources-uc3-kstreams - optional: true - - name: benchmark-resources-uc4-kstreams - configMap: - name: benchmark-resources-uc4-kstreams - optional: true - - name: benchmark-resources-uc1-flink - configMap: - name: benchmark-resources-uc1-flink - optional: true - - name: benchmark-resources-uc2-flink - configMap: - name: benchmark-resources-uc2-flink - optional: true - - name: benchmark-resources-uc3-flink - configMap: - name: benchmark-resources-uc3-flink - optional: true - - name: benchmark-resources-uc4-flink - configMap: - name: benchmark-resources-uc4-flink - optional: true - - name: benchmark-resources-custom - configMap: - name: benchmark-resources-custom - optional: true {{- end }} diff --git a/helm/values.yaml b/helm/values.yaml index b0ce0faeaa7989872fdedc308d3d4c507894e0e7..9de0155cf26d26bc20975d8ec6524607ac9a1d43 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -3,7 +3,7 @@ ### kafkaClient: - enabled: true + enabled: false nodeSelector: {} @@ -155,7 +155,10 @@ cp-helm-charts: ### kafka-lag-exporter: enabled: true + image: + pullPolicy: IfNotPresent nodeSelector: {} + clusters: - name: "theodolite-cp-kafka" bootstrapBrokers: "theodolite-cp-kafka:9092" @@ -250,6 +253,8 @@ operator: imageTag: latest imagePullPolicy: Always + nodeSelector: {} + sloChecker: lagTrend: enabled: true @@ -263,18 +268,42 @@ operator: imagePullPolicy: Always resultsVolume: - enabled: true - # existingClaim: - # storageClassName: - accessModes: - - ReadWriteOnce - size: 1Gi + persistent: + enabled: false + # existingClaim: + # storageClassName: + accessModes: + - ReadWriteOnce + size: 1Gi accessSidecar: enabled: true image: busybox imageTag: stable imagePullPolicy: IfNotPresent + theodoliteBenchmarks: + resourceConfigMaps: + uc1LoadGenerator: true + uc1Kstreams: true + uc1Flink: true + uc2LoadGenerator: true + uc2Kstreams: true + uc2Flink: true + uc3LoadGenerator: true + uc3Kstreams: true + uc3Flink: true + uc4LoadGenerator: true + uc4Kstreams: true + uc4Flink: true + benchmarks: + uc1Kstreams: true + uc1Flink: true + uc2Kstreams: true + uc2Flink: true + uc3Kstreams: true + uc3Flink: true + uc4Kstreams: true + uc4Flink: true serviceAccount: create: true @@ -291,3 +320,4 @@ randomScheduler: create: true serviceAccount: create: true + nodeSelector: {} diff --git a/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.flink.gradle b/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.flink.gradle index d6d5217667a73a1529d73ac59260bcf47d8cf2e1..333a87bf55bcd0051be05ca91dfe8dc9a2e9e8fa 100644 --- a/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.flink.gradle +++ b/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.flink.gradle @@ -48,19 +48,19 @@ dependencies { implementation 'com.google.guava:guava:24.1-jre' implementation 'com.google.code.gson:gson:2.8.2' implementation 'org.slf4j:slf4j-simple:1.6.1' - compile project(':flink-commons') + implementation project(':flink-commons') //compile group: 'org.apache.kafka', name: 'kafka-clients', version: "2.2.0" - compile group: 'org.apache.flink', name: 'flink-java', version: "${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-streaming-java_${scalaBinaryVersion}", version:"${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-table-api-java-bridge_${scalaBinaryVersion}", version: "${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-table-planner-blink_${scalaBinaryVersion}", version: "${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-connector-kafka_${scalaBinaryVersion}", version: "${flinkVersion}" + implementation "org.apache.flink:flink-java:${flinkVersion}" + implementation "org.apache.flink:flink-streaming-java_${scalaBinaryVersion}:${flinkVersion}" + implementation "org.apache.flink:flink-table-api-java-bridge_${scalaBinaryVersion}:${flinkVersion}" + implementation "org.apache.flink:flink-table-planner-blink_${scalaBinaryVersion}:${flinkVersion}" + implementation "org.apache.flink:flink-connector-kafka_${scalaBinaryVersion}:${flinkVersion}" implementation "org.apache.flink:flink-avro:${flinkVersion}" implementation "org.apache.flink:flink-avro-confluent-registry:${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-runtime-web_${scalaBinaryVersion}", version: "${flinkVersion}" // TODO: remove after development - compile group: 'org.apache.flink', name: "flink-statebackend-rocksdb_${scalaBinaryVersion}", version: "${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-metrics-prometheus_${scalaBinaryVersion}", version: "${flinkVersion}" + implementation "org.apache.flink:flink-runtime-web_${scalaBinaryVersion}:${flinkVersion}" // For debugging + implementation "org.apache.flink:flink-statebackend-rocksdb_${scalaBinaryVersion}:${flinkVersion}" + implementation "org.apache.flink:flink-metrics-prometheus_${scalaBinaryVersion}:${flinkVersion}" // Use JUnit test framework testImplementation 'junit:junit:4.12' diff --git a/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.java-conventions.gradle b/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.java-conventions.gradle index c546156736017d742ddbdbf8b9f1f13726dc5ed8..5b0e2a8a1211653428b296b11b14c1531e40e46b 100644 --- a/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.java-conventions.gradle +++ b/theodolite-benchmarks/buildSrc/src/main/groovy/theodolite.java-conventions.gradle @@ -50,7 +50,7 @@ pmd { ruleSets = [] // Gradle requires to clean the rule sets first ruleSetFiles = files("$rootProject.projectDir/config/pmd.xml") ignoreFailures = false - toolVersion = "6.8.0" + toolVersion = "6.13.0" } checkstyle { @@ -58,7 +58,7 @@ checkstyle { configFile = file("$rootProject.projectDir/config/checkstyle.xml") maxWarnings = 0 ignoreFailures = false - toolVersion = "8.12" + toolVersion = "8.19" } spotbugs { diff --git a/theodolite-benchmarks/definitions/install-configmaps.sh b/theodolite-benchmarks/definitions/install-configmaps.sh index 7ddd606a162185993ce402ef4d3b84d8d00eb82c..841a293bbb77c4960a2532a13a009a42227223d3 100755 --- a/theodolite-benchmarks/definitions/install-configmaps.sh +++ b/theodolite-benchmarks/definitions/install-configmaps.sh @@ -1,8 +1,17 @@ +# Flink kubectl create configmap benchmark-resources-uc1-flink --from-file uc1-flink/resources kubectl create configmap benchmark-resources-uc2-flink --from-file uc2-flink/resources kubectl create configmap benchmark-resources-uc3-flink --from-file uc3-flink/resources kubectl create configmap benchmark-resources-uc4-flink --from-file uc4-flink/resources + +# Kafka Streams kubectl create configmap benchmark-resources-uc1-kstreams --from-file uc1-kstreams/resources kubectl create configmap benchmark-resources-uc2-kstreams --from-file uc2-kstreams/resources kubectl create configmap benchmark-resources-uc3-kstreams --from-file uc3-kstreams/resources -kubectl create configmap benchmark-resources-uc4-kstreams --from-file uc4-kstreams/resources \ No newline at end of file +kubectl create configmap benchmark-resources-uc4-kstreams --from-file uc4-kstreams/resources + +# Load Generator +kubectl create configmap benchmark-resources-uc1-load-generator --from-file uc1-load-generator/resources +kubectl create configmap benchmark-resources-uc2-load-generator --from-file uc2-load-generator/resources +kubectl create configmap benchmark-resources-uc3-load-generator --from-file uc3-load-generator/resources +kubectl create configmap benchmark-resources-uc4-load-generator --from-file uc4-load-generator/resources diff --git a/theodolite-benchmarks/definitions/uc1-flink/uc1-flink-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc1-flink/uc1-flink-benchmark-operator.yaml index 3e16e486446d568d2cac0fe5196ab7446be25978..89bac41ee5c8dcefa628b3cb01052df5a1df9292 100644 --- a/theodolite-benchmarks/definitions/uc1-flink/uc1-flink-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc1-flink/uc1-flink-benchmark-operator.yaml @@ -3,29 +3,37 @@ kind: benchmark metadata: name: uc1-flink spec: - appResource: - - "uc1-flink/flink-configuration-configmap.yaml" - - "uc1-flink/taskmanager-deployment.yaml" - - "uc1-flink/taskmanager-service.yaml" - - "uc1-flink/service-monitor.yaml" - - "uc1-flink/jobmanager-service.yaml" - - "uc1-flink/jobmanager-deployment.yaml" - #- "uc1-flink/jobmanager-rest-service.yaml" - loadGenResource: - - "uc1-kstreams/uc1-load-generator-deployment.yaml" - - "uc1-kstreams/uc1-load-generator-service.yaml" + sut: + resources: + - configMap: + name: "benchmark-resources-uc1-flink" + files: + - "flink-configuration-configmap.yaml" + - "taskmanager-deployment.yaml" + - "taskmanager-service.yaml" + - "service-monitor.yaml" + - "jobmanager-service.yaml" + - "jobmanager-deployment.yaml" + #- "jobmanager-rest-service.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc1-load-generator" + files: + - "uc1-load-generator-deployment.yaml" + - "uc1-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: - type: "ReplicaPatcher" - resource: "uc1-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" - type: "EnvVarPatcher" - resource: "uc1-flink/jobmanager-deployment.yaml" + resource: "jobmanager-deployment.yaml" properties: container: "jobmanager" variableName: "PARALLELISM" - type: "EnvVarPatcher" # required? - resource: "uc1-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" properties: container: "taskmanager" variableName: "PARALLELISM" @@ -33,12 +41,12 @@ spec: - typeName: "NumSensors" patchers: - type: "EnvVarPatcher" - resource: "uc1-kstreams/uc1-load-generator-deployment.yaml" + resource: "uc1-load-generator-deployment.yaml" properties: container: "workload-generator" variableName: "NUM_SENSORS" - type: NumSensorsLoadGeneratorReplicaPatcher - resource: "uc1-kstreams/uc1-load-generator-deployment.yaml" + resource: "uc1-load-generator-deployment.yaml" properties: loadGenMaxRecords: "150000" kafkaConfig: diff --git a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-operator.yaml deleted file mode 100644 index 8bcc7d5a1d750eed140527e7c6176a881bc9e6e1..0000000000000000000000000000000000000000 --- a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-operator.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: theodolite.com/v1 -kind: benchmark -metadata: - name: uc1-kstreams -spec: - appResource: - - "uc1-kstreams/uc1-kstreams-deployment.yaml" - - "uc1-kstreams/uc1-kstreams-service.yaml" - - "uc1-kstreams/uc1-jmx-configmap.yaml" - - "uc1-kstreams/uc1-service-monitor.yaml" - loadGenResource: - - "uc1-kstreams/uc1-load-generator-deployment.yaml" - - "uc1-kstreams/uc1-load-generator-service.yaml" - resourceTypes: - - typeName: "Instances" - patchers: - - type: "ReplicaPatcher" - resource: "uc1-kstreams/uc1-kstreams-deployment.yaml" - loadTypes: - - typeName: "NumSensors" - patchers: - - type: "EnvVarPatcher" - resource: "uc1-kstreams/uc1-load-generator-deployment.yaml" - properties: - container: "workload-generator" - variableName: "NUM_SENSORS" - - type: NumSensorsLoadGeneratorReplicaPatcher - resource: "uc1-kstreams/uc1-load-generator-deployment.yaml" - properties: - loadGenMaxRecords: "150000" - kafkaConfig: - bootstrapServer: "theodolite-cp-kafka:9092" - topics: - - name: "input" - numPartitions: 40 - replicationFactor: 1 diff --git a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-kstreams-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-kstreams-benchmark-operator.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fb5557c2df8b483164d3c1000717db4c7cface81 --- /dev/null +++ b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-kstreams-benchmark-operator.yaml @@ -0,0 +1,44 @@ +apiVersion: theodolite.com/v1 +kind: benchmark +metadata: + name: uc1-kstreams +spec: + sut: + resources: + - configMap: + name: "benchmark-resources-uc1-kstreams" + files: + - "uc1-kstreams-deployment.yaml" + - "uc1-kstreams-service.yaml" + - "uc1-jmx-configmap.yaml" + - "uc1-service-monitor.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc1-load-generator" + files: + - "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: + container: "workload-generator" + variableName: "NUM_SENSORS" + - type: NumSensorsLoadGeneratorReplicaPatcher + resource: "uc1-load-generator-deployment.yaml" + properties: + loadGenMaxRecords: "150000" + kafkaConfig: + bootstrapServer: "theodolite-cp-kafka:9092" + topics: + - name: "input" + numPartitions: 40 + replicationFactor: 1 diff --git a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-kstreams-benchmark-standalone.yaml similarity index 59% rename from theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-standalone.yaml rename to theodolite-benchmarks/definitions/uc1-kstreams/uc1-kstreams-benchmark-standalone.yaml index 871210c213b70070e2aae8f4986058763be74b7e..5aaf87e724a4e8c728c3c15b998cb927ff57f3d5 100644 --- a/theodolite-benchmarks/definitions/uc1-kstreams/uc1-benchmark-standalone.yaml +++ b/theodolite-benchmarks/definitions/uc1-kstreams/uc1-kstreams-benchmark-standalone.yaml @@ -1,12 +1,20 @@ name: "uc1-kstreams" -appResource: - - "uc1-kstreams-deployment.yaml" - - "uc1-kstreams-service.yaml" - - "uc1-jmx-configmap.yaml" - - "uc1-service-monitor.yaml" -loadGenResource: - - "uc1-load-generator-deployment.yaml" - - "uc1-load-generator-service.yaml" +sut: + resources: + - configMap: + name: "benchmark-resources-uc1-kstreams" + files: + - "uc1-kstreams-deployment.yaml" + - "uc1-kstreams-service.yaml" + - "uc1-jmx-configmap.yaml" + - "uc1-service-monitor.yaml" +loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc1-load-generator" + files: + - "uc1-load-generator-deployment.yaml" + - "uc1-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: diff --git a/theodolite-benchmarks/definitions/uc1-kstreams/resources/uc1-load-generator-deployment.yaml b/theodolite-benchmarks/definitions/uc1-load-generator/resources/uc1-load-generator-deployment.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc1-kstreams/resources/uc1-load-generator-deployment.yaml rename to theodolite-benchmarks/definitions/uc1-load-generator/resources/uc1-load-generator-deployment.yaml diff --git a/theodolite-benchmarks/definitions/uc1-kstreams/resources/uc1-load-generator-service.yaml b/theodolite-benchmarks/definitions/uc1-load-generator/resources/uc1-load-generator-service.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc1-kstreams/resources/uc1-load-generator-service.yaml rename to theodolite-benchmarks/definitions/uc1-load-generator/resources/uc1-load-generator-service.yaml diff --git a/theodolite-benchmarks/definitions/uc2-flink/uc2-flink-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc2-flink/uc2-flink-benchmark-operator.yaml index ab335cc4f9f8413dd7871fc2184491235aad67e4..206fbf9683659fcc074341d7077da04c36909b75 100644 --- a/theodolite-benchmarks/definitions/uc2-flink/uc2-flink-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc2-flink/uc2-flink-benchmark-operator.yaml @@ -3,29 +3,37 @@ kind: benchmark metadata: name: uc2-flink spec: - appResource: - - "uc2-flink/flink-configuration-configmap.yaml" - - "uc2-flink/taskmanager-deployment.yaml" - - "uc2-flink/taskmanager-service.yaml" - - "uc2-flink/service-monitor.yaml" - - "uc2-flink/jobmanager-service.yaml" - - "uc2-flink/jobmanager-deployment.yaml" - #- "uc2-flink/jobmanager-rest-service.yaml" - loadGenResource: - - "uc2-kstreams/uc2-load-generator-deployment.yaml" - - "uc2-kstreams/uc2-load-generator-service.yaml" + sut: + resources: + - configMap: + name: "benchmark-resources-uc2-flink" + files: + - "flink-configuration-configmap.yaml" + - "taskmanager-deployment.yaml" + - "taskmanager-service.yaml" + - "service-monitor.yaml" + - "jobmanager-service.yaml" + - "jobmanager-deployment.yaml" + #- "jobmanager-rest-service.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc2-load-generator" + files: + - "uc2-load-generator-deployment.yaml" + - "uc2-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: - type: "ReplicaPatcher" - resource: "uc2-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" - type: "EnvVarPatcher" - resource: "uc2-flink/jobmanager-deployment.yaml" + resource: "jobmanager-deployment.yaml" properties: container: "jobmanager" variableName: "PARALLELISM" - type: "EnvVarPatcher" # required? - resource: "uc2-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" properties: container: "taskmanager" variableName: "PARALLELISM" @@ -33,12 +41,12 @@ spec: - typeName: "NumSensors" patchers: - type: "EnvVarPatcher" - resource: "uc2-kstreams/uc2-load-generator-deployment.yaml" + resource: "uc2-load-generator-deployment.yaml" properties: container: "workload-generator" variableName: "NUM_SENSORS" - type: NumSensorsLoadGeneratorReplicaPatcher - resource: "uc2-kstreams/uc2-load-generator-deployment.yaml" + resource: "uc2-load-generator-deployment.yaml" properties: loadGenMaxRecords: "150000" kafkaConfig: diff --git a/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc2-kstreams/uc2-kstreams-benchmark-operator.yaml similarity index 53% rename from theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-operator.yaml rename to theodolite-benchmarks/definitions/uc2-kstreams/uc2-kstreams-benchmark-operator.yaml index c71318c95ceb9d462f64e19b135ce59b43b03099..0db22fa95f46d1cb484fa1a7730b8b6801dac67c 100644 --- a/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc2-kstreams/uc2-kstreams-benchmark-operator.yaml @@ -3,29 +3,37 @@ kind: benchmark metadata: name: uc2-kstreams spec: - appResource: - - "uc2-kstreams/uc2-kstreams-deployment.yaml" - - "uc2-kstreams/uc2-kstreams-service.yaml" - - "uc2-kstreams/uc2-jmx-configmap.yaml" - - "uc2-kstreams/uc2-service-monitor.yaml" - loadGenResource: - - "uc2-kstreams/uc2-load-generator-deployment.yaml" - - "uc2-kstreams/uc2-load-generator-service.yaml" + sut: + resources: + - configMap: + name: "benchmark-resources-uc2-kstreams" + files: + - "uc2-kstreams-deployment.yaml" + - "uc2-kstreams-service.yaml" + - "uc2-jmx-configmap.yaml" + - "uc2-service-monitor.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc2-load-generator" + files: + - "uc2-load-generator-deployment.yaml" + - "uc2-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: - type: "ReplicaPatcher" - resource: "uc2-kstreams/uc2-kstreams-deployment.yaml" + resource: "uc2-kstreams-deployment.yaml" loadTypes: - typeName: "NumSensors" patchers: - type: "EnvVarPatcher" - resource: "uc2-kstreams/uc2-load-generator-deployment.yaml" + resource: "uc2-load-generator-deployment.yaml" properties: container: "workload-generator" variableName: "NUM_SENSORS" - type: NumSensorsLoadGeneratorReplicaPatcher - resource: "uc2-kstreams/uc2-load-generator-deployment.yaml" + resource: "uc2-load-generator-deployment.yaml" properties: loadGenMaxRecords: "150000" kafkaConfig: diff --git a/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc2-kstreams/uc2-kstreams-benchmark-standalone.yaml similarity index 63% rename from theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-standalone.yaml rename to theodolite-benchmarks/definitions/uc2-kstreams/uc2-kstreams-benchmark-standalone.yaml index 48269b38a086f074ead80964df3bd4633742743e..67376d76bf0a7cc4cd47563a1d8da8dc0aa3b944 100644 --- a/theodolite-benchmarks/definitions/uc2-kstreams/uc2-benchmark-standalone.yaml +++ b/theodolite-benchmarks/definitions/uc2-kstreams/uc2-kstreams-benchmark-standalone.yaml @@ -1,12 +1,20 @@ name: "uc2-kstreams" -appResource: - - "uc2-kstreams-deployment.yaml" - - "uc2-kstreams-service.yaml" - - "uc2-jmx-configmap.yaml" - - "uc2-service-monitor.yaml" -loadGenResource: - - "uc2-load-generator-deployment.yaml" - - "uc2-load-generator-service.yaml" +sut: + resources: + - configMap: + name: "benchmark-resources-uc2-kstreams" + files: + - "uc2-kstreams-deployment.yaml" + - "uc2-kstreams-service.yaml" + - "uc2-jmx-configmap.yaml" + - "uc2-service-monitor.yaml" +loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc2-load-generator" + files: + - "uc2-load-generator-deployment.yaml" + - "uc2-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: diff --git a/theodolite-benchmarks/definitions/uc2-kstreams/resources/uc2-load-generator-deployment.yaml b/theodolite-benchmarks/definitions/uc2-load-generator/resources/uc2-load-generator-deployment.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc2-kstreams/resources/uc2-load-generator-deployment.yaml rename to theodolite-benchmarks/definitions/uc2-load-generator/resources/uc2-load-generator-deployment.yaml diff --git a/theodolite-benchmarks/definitions/uc2-kstreams/resources/uc2-load-generator-service.yaml b/theodolite-benchmarks/definitions/uc2-load-generator/resources/uc2-load-generator-service.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc2-kstreams/resources/uc2-load-generator-service.yaml rename to theodolite-benchmarks/definitions/uc2-load-generator/resources/uc2-load-generator-service.yaml diff --git a/theodolite-benchmarks/definitions/uc3-flink/uc3-flink-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc3-flink/uc3-flink-benchmark-operator.yaml index bc881d83d622f49409c4b2023b7fd9445038c2e8..47b64d9890fc0f300ee1bd8e67acbdf7c8c4e4f9 100644 --- a/theodolite-benchmarks/definitions/uc3-flink/uc3-flink-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc3-flink/uc3-flink-benchmark-operator.yaml @@ -3,29 +3,37 @@ kind: benchmark metadata: name: uc3-flink spec: - appResource: - - "uc3-flink/flink-configuration-configmap.yaml" - - "uc3-flink/taskmanager-deployment.yaml" - - "uc3-flink/taskmanager-service.yaml" - - "uc3-flink/service-monitor.yaml" - - "uc3-flink/jobmanager-service.yaml" - - "uc3-flink/jobmanager-deployment.yaml" - #- "uc3-flink/jobmanager-rest-service.yaml" - loadGenResource: - - "uc3-kstreams/uc3-load-generator-deployment.yaml" - - "uc3-kstreams/uc3-load-generator-service.yaml" + sut: + resources: + - configMap: + name: "benchmark-resources-uc3-flink" + files: + - "flink-configuration-configmap.yaml" + - "taskmanager-deployment.yaml" + - "taskmanager-service.yaml" + - "service-monitor.yaml" + - "jobmanager-service.yaml" + - "jobmanager-deployment.yaml" + #- "jobmanager-rest-service.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc3-load-generator" + files: + - "uc3-load-generator-deployment.yaml" + - "uc3-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: - type: "ReplicaPatcher" - resource: "uc3-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" - type: "EnvVarPatcher" - resource: "uc3-flink/jobmanager-deployment.yaml" + resource: "jobmanager-deployment.yaml" properties: container: "jobmanager" variableName: "PARALLELISM" - type: "EnvVarPatcher" # required? - resource: "uc3-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" properties: container: "taskmanager" variableName: "PARALLELISM" @@ -33,12 +41,12 @@ spec: - typeName: "NumSensors" patchers: - type: "EnvVarPatcher" - resource: "uc3-kstreams/uc3-load-generator-deployment.yaml" + resource: "uc3-load-generator-deployment.yaml" properties: container: "workload-generator" variableName: "NUM_SENSORS" - type: NumSensorsLoadGeneratorReplicaPatcher - resource: "uc3-kstreams/uc3-load-generator-deployment.yaml" + resource: "uc3-load-generator-deployment.yaml" properties: loadGenMaxRecords: "150000" kafkaConfig: diff --git a/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc3-kstreams/uc3-kstreams-benchmark-operator.yaml similarity index 54% rename from theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-operator.yaml rename to theodolite-benchmarks/definitions/uc3-kstreams/uc3-kstreams-benchmark-operator.yaml index cc10020b17c7a31b61f5fdaf6963be9fda75865f..25374ad92a32782857cea5924ea6482060832eac 100644 --- a/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc3-kstreams/uc3-kstreams-benchmark-operator.yaml @@ -3,29 +3,37 @@ kind: benchmark metadata: name: uc3-kstreams spec: - appResource: - - "uc3-kstreams/uc3-kstreams-deployment.yaml" - - "uc3-kstreams/uc3-kstreams-service.yaml" - - "uc3-kstreams/uc3-jmx-configmap.yaml" - - "uc3-kstreams/uc3-service-monitor.yaml" - loadGenResource: - - "uc3-kstreams/uc3-load-generator-deployment.yaml" - - "uc3-kstreams/uc3-load-generator-service.yaml" + sut: + resources: + - configMap: + name: "benchmark-resources-uc3-kstreams" + files: + - "uc3-kstreams-deployment.yaml" + - "uc3-kstreams-service.yaml" + - "uc3-jmx-configmap.yaml" + - "uc3-service-monitor.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc3-load-generator" + files: + - "uc3-load-generator-deployment.yaml" + - "uc3-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: - type: "ReplicaPatcher" - resource: "uc3-kstreams/uc3-kstreams-deployment.yaml" + resource: "uc3-kstreams-deployment.yaml" loadTypes: - typeName: "NumSensors" patchers: - type: "EnvVarPatcher" - resource: "uc3-kstreams/uc3-load-generator-deployment.yaml" + resource: "uc3-load-generator-deployment.yaml" properties: container: "workload-generator" variableName: "NUM_SENSORS" - type: NumSensorsLoadGeneratorReplicaPatcher - resource: "uc3-kstreams/uc3-load-generator-deployment.yaml" + resource: "uc3-load-generator-deployment.yaml" properties: loadGenMaxRecords: "150000" kafkaConfig: diff --git a/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc3-kstreams/uc3-kstreams-benchmark-standalone.yaml similarity index 64% rename from theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-standalone.yaml rename to theodolite-benchmarks/definitions/uc3-kstreams/uc3-kstreams-benchmark-standalone.yaml index 0c2311388f1dfa87e8a182eb8399020bc83ae4ce..aa92913d2c992835078174747ea849ce296c3eb1 100644 --- a/theodolite-benchmarks/definitions/uc3-kstreams/uc3-benchmark-standalone.yaml +++ b/theodolite-benchmarks/definitions/uc3-kstreams/uc3-kstreams-benchmark-standalone.yaml @@ -1,12 +1,20 @@ name: "uc3-kstreams" -appResource: - - "uc3-kstreams-deployment.yaml" - - "uc3-kstreams-service.yaml" - - "uc3-jmx-configmap.yaml" - - "uc3-service-monitor.yaml" -loadGenResource: - - "uc3-load-generator-deployment.yaml" - - "uc3-load-generator-service.yaml" +sut: + resources: + - configMap: + name: "benchmark-resources-uc3-kstreams" + files: + - "uc3-kstreams-deployment.yaml" + - "uc3-kstreams-service.yaml" + - "uc3-jmx-configmap.yaml" + - "uc3-service-monitor.yaml" +loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc3-load-generator" + files: + - "uc3-load-generator-deployment.yaml" + - "uc3-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: diff --git a/theodolite-benchmarks/definitions/uc3-kstreams/resources/uc3-load-generator-deployment.yaml b/theodolite-benchmarks/definitions/uc3-load-generator/resources/uc3-load-generator-deployment.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc3-kstreams/resources/uc3-load-generator-deployment.yaml rename to theodolite-benchmarks/definitions/uc3-load-generator/resources/uc3-load-generator-deployment.yaml diff --git a/theodolite-benchmarks/definitions/uc3-kstreams/resources/uc3-load-generator-service.yaml b/theodolite-benchmarks/definitions/uc3-load-generator/resources/uc3-load-generator-service.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc3-kstreams/resources/uc3-load-generator-service.yaml rename to theodolite-benchmarks/definitions/uc3-load-generator/resources/uc3-load-generator-service.yaml diff --git a/theodolite-benchmarks/definitions/uc4-flink/uc4-flink-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc4-flink/uc4-flink-benchmark-operator.yaml index 9979f540ae343a065d8ca483fa9c5934fc550a46..8a73f5b0f87198def7b152ea52008e3d4a1aa4ee 100644 --- a/theodolite-benchmarks/definitions/uc4-flink/uc4-flink-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc4-flink/uc4-flink-benchmark-operator.yaml @@ -3,29 +3,37 @@ kind: benchmark metadata: name: uc4-flink spec: - appResource: - - "uc4-flink/flink-configuration-configmap.yaml" - - "uc4-flink/taskmanager-deployment.yaml" - - "uc4-flink/taskmanager-service.yaml" - - "uc4-flink/service-monitor.yaml" - - "uc4-flink/jobmanager-service.yaml" - - "uc4-flink/jobmanager-deployment.yaml" - #- "uc4-flink/jobmanager-rest-service.yaml" - loadGenResource: - - "uc4-kstreams/uc4-load-generator-deployment.yaml" - - "uc4-kstreams/uc4-load-generator-service.yaml" + sut: + resources: + - configMap: + name: "benchmark-resources-uc4-flink" + files: + - "flink-configuration-configmap.yaml" + - "taskmanager-deployment.yaml" + - "taskmanager-service.yaml" + - "service-monitor.yaml" + - "jobmanager-service.yaml" + - "jobmanager-deployment.yaml" + #- "jobmanager-rest-service.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc4-load-generator" + files: + - "uc4-load-generator-deployment.yaml" + - "uc4-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: - type: "ReplicaPatcher" - resource: "uc4-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" - type: "EnvVarPatcher" - resource: "uc4-flink/jobmanager-deployment.yaml" + resource: "jobmanager-deployment.yaml" properties: container: "jobmanager" variableName: "PARALLELISM" - type: "EnvVarPatcher" # required? - resource: "uc4-flink/taskmanager-deployment.yaml" + resource: "taskmanager-deployment.yaml" properties: container: "taskmanager" variableName: "PARALLELISM" @@ -33,12 +41,12 @@ spec: - typeName: "NumNestedGroups" patchers: - type: "EnvVarPatcher" - resource: "uc4-kstreams/uc4-load-generator-deployment.yaml" + resource: "uc4-load-generator-deployment.yaml" properties: container: "workload-generator" variableName: "NUM_NESTED_GROUPS" - type: NumNestedGroupsLoadGeneratorReplicaPatcher - resource: "uc4-kstreams/uc4-load-generator-deployment.yaml" + resource: "uc4-load-generator-deployment.yaml" properties: loadGenMaxRecords: "150000" numSensors: "4.0" diff --git a/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-operator.yaml b/theodolite-benchmarks/definitions/uc4-kstreams/uc4-kstreams-benchmark-operator.yaml similarity index 59% rename from theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-operator.yaml rename to theodolite-benchmarks/definitions/uc4-kstreams/uc4-kstreams-benchmark-operator.yaml index 61cdfeeea5298d05cca5f5a44cdb4bdf9f108b7c..655db2fd4122c9e0e844eed3bfe7c0a878c6d7ec 100644 --- a/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-operator.yaml +++ b/theodolite-benchmarks/definitions/uc4-kstreams/uc4-kstreams-benchmark-operator.yaml @@ -3,29 +3,37 @@ kind: benchmark metadata: name: uc4-kstreams spec: - appResource: - - "uc4-kstreams/uc4-kstreams-deployment.yaml" - - "uc4-kstreams/uc4-kstreams-service.yaml" - - "uc4-kstreams/uc4-jmx-configmap.yaml" - - "uc4-kstreams/uc4-service-monitor.yaml" - loadGenResource: - - "uc4-kstreams/uc4-load-generator-deployment.yaml" - - "uc4-kstreams/uc4-load-generator-service.yaml" + sut: + resources: + - configMap: + name: "benchmark-resources-uc4-kstreams" + files: + - "uc4-kstreams-deployment.yaml" + - "uc4-kstreams-service.yaml" + - "uc4-jmx-configmap.yaml" + - "uc4-service-monitor.yaml" + loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc4-load-generator" + files: + - "uc4-load-generator-deployment.yaml" + - "uc4-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: - type: "ReplicaPatcher" - resource: "uc4-kstreams/uc4-kstreams-deployment.yaml" + resource: "uc4-kstreams-deployment.yaml" loadTypes: - typeName: "NumNestedGroups" patchers: - type: "EnvVarPatcher" - resource: "uc4-kstreams/uc4-load-generator-deployment.yaml" + resource: "uc4-load-generator-deployment.yaml" properties: container: "workload-generator" variableName: "NUM_SENSORS" - type: NumNestedGroupsLoadGeneratorReplicaPatcher - resource: "uc4-kstreams/uc4-load-generator-deployment.yaml" + resource: "uc4-load-generator-deployment.yaml" properties: loadGenMaxRecords: "150000" numSensors: "4.0" diff --git a/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-standalone.yaml b/theodolite-benchmarks/definitions/uc4-kstreams/uc4-kstreams-benchmark-standalone.yaml similarity index 68% rename from theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-standalone.yaml rename to theodolite-benchmarks/definitions/uc4-kstreams/uc4-kstreams-benchmark-standalone.yaml index ec7a67db4ea24547bc23d5c57e7b907ba489859c..5c50b6f95d796941c0b2830549ef825f4a4ff6fb 100644 --- a/theodolite-benchmarks/definitions/uc4-kstreams/uc4-benchmark-standalone.yaml +++ b/theodolite-benchmarks/definitions/uc4-kstreams/uc4-kstreams-benchmark-standalone.yaml @@ -1,12 +1,20 @@ name: "uc4-kstreams" -appResource: - - "uc4-kstreams-deployment.yaml" - - "uc4-kstreams-service.yaml" - - "uc4-jmx-configmap.yaml" - - "uc4-service-monitor.yaml" -loadGenResource: - - "uc4-load-generator-deployment.yaml" - - "uc4-load-generator-service.yaml" +sut: + resources: + - configMap: + name: "benchmark-resources-uc4-kstreams" + files: + - "uc4-kstreams-deployment.yaml" + - "uc4-kstreams-service.yaml" + - "uc4-jmx-configmap.yaml" + - "uc4-service-monitor.yaml" +loadGenerator: + resources: + - configMap: + name: "benchmark-resources-uc4-load-generator" + files: + - "uc4-load-generator-deployment.yaml" + - "uc4-load-generator-service.yaml" resourceTypes: - typeName: "Instances" patchers: diff --git a/theodolite-benchmarks/definitions/uc4-kstreams/resources/uc4-load-generator-deployment.yaml b/theodolite-benchmarks/definitions/uc4-load-generator/resources/uc4-load-generator-deployment.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc4-kstreams/resources/uc4-load-generator-deployment.yaml rename to theodolite-benchmarks/definitions/uc4-load-generator/resources/uc4-load-generator-deployment.yaml diff --git a/theodolite-benchmarks/definitions/uc4-kstreams/resources/uc4-load-generator-service.yaml b/theodolite-benchmarks/definitions/uc4-load-generator/resources/uc4-load-generator-service.yaml similarity index 100% rename from theodolite-benchmarks/definitions/uc4-kstreams/resources/uc4-load-generator-service.yaml rename to theodolite-benchmarks/definitions/uc4-load-generator/resources/uc4-load-generator-service.yaml diff --git a/theodolite-benchmarks/docker-test/README.md b/theodolite-benchmarks/docker-test/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fd1e9bf4730f897273be45a022ad2adeae1b7e6e --- /dev/null +++ b/theodolite-benchmarks/docker-test/README.md @@ -0,0 +1,38 @@ +# Docker Compose Files for Testing + +This directory contains Docker Compose files, which help testing Benchmark implementations. +For each stream processing engine (Kafka Streams and Flink) and Benchmark (UC1-4), a Docker Compose file is provided +in the corresponding subdirectory. + +## Full Dockerized Testing + +Running the load generator, the benchmark and all required infrastructure (Kafka etc.) is easy. Simply, `cd` into the +directory of the benchmark implementation Compose file and *up* it. +For example: + +```sh +cd uc1-kstreams-docker-compose/ +docker-compose up -d +``` + +On less powerful hardware, starting all containers together might fail. In such cases, it usually helps to first *up* +Kafka and ZooKeeper (`docker-compose up -d kafka zookeeper`), then after some delay the Schema Registry +(`docker-compose up -d schema-registry`) and finally, after some more further delay, the rest (`docker-compose up -d`). + +To tear down the entire Docker Compose configuration: + +```sh +docker-compose down +``` + +## Benchmark (+ Load Generator) on Host, Infrastructure in Docker + +For development and debugging purposes, it is often required to run the benchmark and/or the load generator directly on +the host, for example, from the IDE or Gradle. In such cases, the following adjustments have to be made to the +`docker-compose.yaml` file: + +1. Comment out the services that you intend to run locally. +2. Uncomment the `ports` block in the Kafka and the Schema Registry services. + +You can now connect to Kafka from your host system with bootstrap server `localhost:19092` and contact the Schema +Registry via `localhost:8081`. **Pay attention to the Kafka port, which is *19092* instead of the default one *9092*.** diff --git a/theodolite-benchmarks/docker-test/uc1-flink-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc1-flink-docker-compose/docker-compose.yml index aa35ac2d1dee01cdf25d2eb2ac77bd056865479a..419c9cfb741578cccd91845c8164d4e5554d2ab6 100755 --- a/theodolite-benchmarks/docker-test/uc1-flink-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc1-flink-docker-compose/docker-compose.yml @@ -3,7 +3,7 @@ services: zookeeper: image: confluentinc/cp-zookeeper expose: - - "9092" + - "2181" environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: @@ -37,7 +37,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/docker-test/uc1-kstreams-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc1-kstreams-docker-compose/docker-compose.yml index 403becacff5a386eddfaa8e59fe7873d2adb006c..cebf3676e92f8ececa5b6707df156f9f22f3be38 100755 --- a/theodolite-benchmarks/docker-test/uc1-kstreams-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc1-kstreams-docker-compose/docker-compose.yml @@ -3,7 +3,7 @@ services: zookeeper: image: confluentinc/cp-zookeeper expose: - - "9092" + - "2181" environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: @@ -45,7 +45,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/docker-test/uc2-flink-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc2-flink-docker-compose/docker-compose.yml index a8bf56d52c1be7fea3f172d86f6deac27fcc24f7..c4265702b6f2b833e7b3792a787e3d8a67486ac7 100755 --- a/theodolite-benchmarks/docker-test/uc2-flink-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc2-flink-docker-compose/docker-compose.yml @@ -1,10 +1,9 @@ version: '2' services: zookeeper: - #image: wurstmeister/zookeeper image: confluentinc/cp-zookeeper - ports: - - "2181:2181" + expose: + - "2181" environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: @@ -38,7 +37,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/docker-test/uc2-kstreams-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc2-kstreams-docker-compose/docker-compose.yml index 20d2c62dac13af29ec50439670308f2911f0d57a..b520611e4855f6e942fab62b02d27d5f360860d1 100755 --- a/theodolite-benchmarks/docker-test/uc2-kstreams-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc2-kstreams-docker-compose/docker-compose.yml @@ -1,10 +1,9 @@ version: '2' services: zookeeper: - #image: wurstmeister/zookeeper image: confluentinc/cp-zookeeper - ports: - - "2181:2181" + expose: + - "2181" environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: @@ -47,7 +46,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/docker-test/uc3-flink-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc3-flink-docker-compose/docker-compose.yml index 9999caf046e844d066200ecfbf15d3351c167d31..2c69a659c6ed1e83c149e699484ec148196806c5 100755 --- a/theodolite-benchmarks/docker-test/uc3-flink-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc3-flink-docker-compose/docker-compose.yml @@ -1,10 +1,9 @@ version: '2' services: zookeeper: - #image: wurstmeister/zookeeper image: confluentinc/cp-zookeeper - ports: - - "2181:2181" + expose: + - "2181" environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: @@ -38,7 +37,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/docker-test/uc3-kstreams-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc3-kstreams-docker-compose/docker-compose.yml index ef16b858536b0d133dc49d002d16cf6c04193297..5ed8e7a673afd825b2e1426fa018db3e00848296 100755 --- a/theodolite-benchmarks/docker-test/uc3-kstreams-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc3-kstreams-docker-compose/docker-compose.yml @@ -1,10 +1,9 @@ version: '2' services: zookeeper: - #image: wurstmeister/zookeeper image: confluentinc/cp-zookeeper - ports: - - "2181:2181" + expose: + - "2181" environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: @@ -32,7 +31,7 @@ services: environment: SCHEMA_REGISTRY_HOST_NAME: schema-registry SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: 'zookeeper:2181' - benchmark: + benchmark: image: ghcr.io/cau-se/theodolite-uc3-kstreams-app:latest depends_on: - schema-registry @@ -46,7 +45,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/docker-test/uc4-flink-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc4-flink-docker-compose/docker-compose.yml index 80720063991100bae2c8c148f14cd6f1a32bb0ff..b6bb905e2a950e23970392f256f16935a7777fed 100755 --- a/theodolite-benchmarks/docker-test/uc4-flink-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc4-flink-docker-compose/docker-compose.yml @@ -37,7 +37,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/docker-test/uc4-kstreams-docker-compose/docker-compose.yml b/theodolite-benchmarks/docker-test/uc4-kstreams-docker-compose/docker-compose.yml index 5e4cb94469f2f6cc8c48694a7ea6c885f066622d..68264b244c16f1a1be7b370bb4e78052d3a8518f 100755 --- a/theodolite-benchmarks/docker-test/uc4-kstreams-docker-compose/docker-compose.yml +++ b/theodolite-benchmarks/docker-test/uc4-kstreams-docker-compose/docker-compose.yml @@ -45,7 +45,7 @@ services: - schema-registry - kafka environment: - BOOTSTRAP_SERVER: uc-wg:5701 + BOOTSTRAP_SERVER: load-generator:5701 PORT: 5701 KAFKA_BOOTSTRAP_SERVERS: kafka:9092 SCHEMA_REGISTRY_URL: http://schema-registry:8081 diff --git a/theodolite-benchmarks/flink-commons/build.gradle b/theodolite-benchmarks/flink-commons/build.gradle index 1b0b9359a406bf2ab16fbbe52631877cf360df2a..0da7c6f93f4e77e1376f5f2d006ec0bf0f398ec8 100644 --- a/theodolite-benchmarks/flink-commons/build.gradle +++ b/theodolite-benchmarks/flink-commons/build.gradle @@ -22,13 +22,14 @@ dependencies { implementation('org.industrial-devops:titan-ccp-common:0.1.0-flink-ready-SNAPSHOT') { changing = true } implementation('org.industrial-devops:titan-ccp-common-kafka:0.1.0-SNAPSHOT') { changing = true } implementation 'com.google.guava:guava:30.1-jre' - compile group: 'org.apache.flink', name: "flink-connector-kafka_${scalaBinaryVersion}", version: "${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-statebackend-rocksdb_${scalaBinaryVersion}", version: "${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-runtime_${scalaBinaryVersion}", version: "${flinkVersion}" - compile group: 'org.apache.flink', name: 'flink-java', version: "${flinkVersion}" - compile group: 'org.apache.flink', name: "flink-streaming-java_${scalaBinaryVersion}", version:"${flinkVersion}" + + implementation "org.apache.flink:flink-java:${flinkVersion}" + implementation "org.apache.flink:flink-connector-kafka_${scalaBinaryVersion}:${flinkVersion}" implementation "org.apache.flink:flink-avro:${flinkVersion}" implementation "org.apache.flink:flink-avro-confluent-registry:${flinkVersion}" + implementation "org.apache.flink:flink-runtime-web_${scalaBinaryVersion}:${flinkVersion}" // For debugging + implementation "org.apache.flink:flink-statebackend-rocksdb_${scalaBinaryVersion}:${flinkVersion}" + implementation "org.apache.flink:flink-metrics-prometheus_${scalaBinaryVersion}:${flinkVersion}" // Use JUnit test framework testImplementation 'junit:junit:4.12' diff --git a/theodolite-benchmarks/flink-commons/src/main/java/theodolite/commons/flink/serialization/StatsSerializer.java b/theodolite-benchmarks/flink-commons/src/main/java/theodolite/commons/flink/serialization/StatsSerializer.java index f1f9870fda73ccec0fc25c5c70665759ab07d893..fe74fbe4b9dcb6ce89d10131de1336bfff40a919 100644 --- a/theodolite-benchmarks/flink-commons/src/main/java/theodolite/commons/flink/serialization/StatsSerializer.java +++ b/theodolite-benchmarks/flink-commons/src/main/java/theodolite/commons/flink/serialization/StatsSerializer.java @@ -5,7 +5,6 @@ import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import com.google.common.math.Stats; - import java.io.Serializable; /** @@ -13,7 +12,7 @@ import java.io.Serializable; */ public class StatsSerializer extends Serializer<Stats> implements Serializable { - private static final long serialVersionUID = -1276866176534267373L; //NOPMD + private static final long serialVersionUID = -1276866176534267373L; // NOPMD @Override public void write(final Kryo kryo, final Output output, final Stats object) { diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/GeneratorAction.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/GeneratorAction.java new file mode 100644 index 0000000000000000000000000000000000000000..11a9cbf2d96bc3a02f3972ba23f2167af06a2ec3 --- /dev/null +++ b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/GeneratorAction.java @@ -0,0 +1,18 @@ +package theodolite.commons.workloadgeneration; + +/** + * Interface representing a record generator action consisting of generating a record and sending + * it. + */ +@FunctionalInterface +interface GeneratorAction { + + void generate(final String key); + + public static <T> GeneratorAction from( + final RecordGenerator<? extends T> generator, + final RecordSender<? super T> sender) { + return key -> sender.send(generator.generate(key)); + } + +} diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/KafkaRecordSender.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/KafkaRecordSender.java index 6e4a43271fbf1e0193c2d39569a0814d1f7935cd..ded7c347c8d6b057581dc63b691df5bb60997791 100644 --- a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/KafkaRecordSender.java +++ b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/KafkaRecordSender.java @@ -53,6 +53,33 @@ public class KafkaRecordSender<T extends SpecificRecord> implements RecordSender avroSerdeFactory.<T>forKeys().serializer()); } + /** + * Write the passed monitoring record to Kafka. + */ + public void write(final T monitoringRecord) { + final ProducerRecord<String, T> record = + new ProducerRecord<>(this.topic, null, this.timestampAccessor.apply(monitoringRecord), + this.keyAccessor.apply(monitoringRecord), monitoringRecord); + + LOGGER.debug("Send record to Kafka topic {}: {}", this.topic, record); + try { + this.producer.send(record); + } catch (final SerializationException e) { + LOGGER.warn( + "Record could not be serialized and thus not sent to Kafka due to exception. Skipping this record.", // NOCS + e); + } + } + + public void terminate() { + this.producer.close(); + } + + @Override + public void send(final T message) { + this.write(message); + } + public static <T extends SpecificRecord> Builder<T> builder( final String bootstrapServers, final String topic, @@ -108,31 +135,4 @@ public class KafkaRecordSender<T extends SpecificRecord> implements RecordSender } } - /** - * Write the passed monitoring record to Kafka. - */ - public void write(final T monitoringRecord) { - final ProducerRecord<String, T> record = - new ProducerRecord<>(this.topic, null, this.timestampAccessor.apply(monitoringRecord), - this.keyAccessor.apply(monitoringRecord), monitoringRecord); - - LOGGER.debug("Send record to Kafka topic {}: {}", this.topic, record); - try { - this.producer.send(record); - } catch (final SerializationException e) { - LOGGER.warn( - "Record could not be serialized and thus not sent to Kafka due to exception. Skipping this record.", // NOCS - e); - } - } - - public void terminate() { - this.producer.close(); - } - - @Override - public void send(final T message) { - this.write(message); - } - } diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGenerator.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGenerator.java index a9a1ce65ac32e3508299c99a38ecd21e4c9461cf..73f064d1ce44ff8a613f9ce0a7b9a64d4bac6c38 100644 --- a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGenerator.java +++ b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGenerator.java @@ -91,12 +91,11 @@ public final class LoadGenerator { new KeySpace(SENSOR_PREFIX_DEFAULT, NUMBER_OF_KEYS_DEFAULT), Duration.ofMillis(PERIOD_MS_DEFAULT))) .setGeneratorConfig(new LoadGeneratorConfig( - TitanMessageGeneratorFactory - .withKafkaConfig( - KAFKA_BOOTSTRAP_SERVERS_DEFAULT, - KAFKA_TOPIC_DEFAULT, - SCHEMA_REGISTRY_URL_DEFAULT) - .forConstantValue(VALUE_DEFAULT))); + TitanRecordGeneratorFactory.forConstantValue(VALUE_DEFAULT), + TitanKafkaSenderFactory.forKafkaConfig( + KAFKA_BOOTSTRAP_SERVERS_DEFAULT, + KAFKA_TOPIC_DEFAULT, + SCHEMA_REGISTRY_URL_DEFAULT))); } /** @@ -170,13 +169,11 @@ public final class LoadGenerator { new KeySpace(SENSOR_PREFIX_DEFAULT, numSensors), Duration.ofMillis(periodMs))) .setGeneratorConfig(new LoadGeneratorConfig( - TitanMessageGeneratorFactory - .withKafkaConfig( - kafkaBootstrapServers, - kafkaInputTopic, - schemaRegistryUrl, - kafkaProperties) - .forConstantValue(value))) + TitanRecordGeneratorFactory.forConstantValue(value), + TitanKafkaSenderFactory.forKafkaConfig( + kafkaBootstrapServers, + kafkaInputTopic, + schemaRegistryUrl))) .withThreads(threads); } diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorConfig.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorConfig.java index 2e907d8e90172288099bc6a1776777c37ae90fff..4b5fea3e4670315ef47d94669b42a3cca4b5d0ae 100644 --- a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorConfig.java +++ b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorConfig.java @@ -5,30 +5,24 @@ package theodolite.commons.workloadgeneration; */ public class LoadGeneratorConfig { - private final MessageGenerator messageGenerator; + private final GeneratorAction messageGenerator; private BeforeAction beforeAction = BeforeAction.doNothing(); private int threads = 1; - public LoadGeneratorConfig(final MessageGenerator messageGenerator) { - this.messageGenerator = messageGenerator; + public <T> LoadGeneratorConfig( + final RecordGenerator<? extends T> generator, + final RecordSender<? super T> sender) { + this.messageGenerator = GeneratorAction.from(generator, sender); } - public LoadGeneratorConfig( - final MessageGenerator messageGenerator, + public <T> LoadGeneratorConfig( + final RecordGenerator<? extends T> generator, + final RecordSender<? super T> sender, final int threads) { - this.messageGenerator = messageGenerator; + this(generator, sender); this.threads = threads; } - public LoadGeneratorExecution buildLoadGeneratorExecution( - final WorkloadDefinition workloadDefinition) { - return new LoadGeneratorExecution(workloadDefinition, this.messageGenerator, this.threads); - } - - public BeforeAction getBeforeAction() { - return this.beforeAction; - } - public void setThreads(final int threads) { this.threads = threads; } @@ -37,6 +31,13 @@ public class LoadGeneratorConfig { this.beforeAction = beforeAction; } + public BeforeAction getBeforeAction() { + return this.beforeAction; + } + public LoadGeneratorExecution buildLoadGeneratorExecution( + final WorkloadDefinition workloadDefinition) { + return new LoadGeneratorExecution(workloadDefinition, this.messageGenerator, this.threads); + } } diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorExecution.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorExecution.java index 3934c3d3499215b37ce96391ff5ae1d5cc135f84..e1a2a7e1bea964b5c69a6cd34374d7b0932bac03 100644 --- a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorExecution.java +++ b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/LoadGeneratorExecution.java @@ -8,25 +8,25 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * A {@link LoadGeneratorExecution} represents the execution of load generator, i.e., it can be + * A {@link LoadGeneratorExecution} represents the execution of a load generator, i.e., it can be * started and stopped. */ -public class LoadGeneratorExecution { +class LoadGeneratorExecution { private static final Logger LOGGER = LoggerFactory.getLogger(LoadGeneratorExecution.class); private final Random random = new Random(); private final WorkloadDefinition workloadDefinition; - private final MessageGenerator messageGenerator; + private final GeneratorAction messageGenerator; private final ScheduledExecutorService executor; /** * Create a new {@link LoadGeneratorExecution} for a given {@link WorkloadDefinition} and a - * {@link MessageGenerator}. Load is generated by the given number of threads. + * {@link GeneratorAction}. Load is generated by the given number of threads. */ public LoadGeneratorExecution( final WorkloadDefinition workloadDefinition, - final MessageGenerator messageGenerator, + final GeneratorAction messageGenerator, final int threads) { this.workloadDefinition = workloadDefinition; this.messageGenerator = messageGenerator; diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/MessageGenerator.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/MessageGenerator.java deleted file mode 100644 index c369f16557d60dae50e22ec7ad820c6a0ab4d137..0000000000000000000000000000000000000000 --- a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/MessageGenerator.java +++ /dev/null @@ -1,18 +0,0 @@ -package theodolite.commons.workloadgeneration; - -/** - * Interface representing a message generator, which sends messages for given keys to some - * destination. - */ -@FunctionalInterface -public interface MessageGenerator { - - void generate(final String key); - - public static <T> MessageGenerator from( - final RecordGenerator<T> generator, - final RecordSender<T> sender) { - return key -> sender.send(generator.generate(key)); - } - -} diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanKafkaSenderFactory.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanKafkaSenderFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..0cdf8d91ea01cc16df5dcd55d77b08c3f4986442 --- /dev/null +++ b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanKafkaSenderFactory.java @@ -0,0 +1,42 @@ +package theodolite.commons.workloadgeneration; + +import java.util.Properties; +import titan.ccp.model.records.ActivePowerRecord; + +/** + * A factory for creating {@link KafkaRecordSender}s that sends Titan {@link ActivePowerRecord}s. + */ +public final class TitanKafkaSenderFactory { + + private TitanKafkaSenderFactory() {} + + /** + * Create a new KafkaRecordSender for {@link ActivePowerRecord}s for the given Kafka + * configuration. + */ + public static KafkaRecordSender<ActivePowerRecord> forKafkaConfig( + final String bootstrapServers, + final String topic, + final String schemaRegistryUrl) { + return forKafkaConfig(bootstrapServers, topic, schemaRegistryUrl, new Properties()); + } + + /** + * Create a new KafkaRecordSender for {@link ActivePowerRecord}s for the given Kafka + * configuration. + */ + public static KafkaRecordSender<ActivePowerRecord> forKafkaConfig( + final String bootstrapServers, + final String topic, + final String schemaRegistryUrl, + final Properties properties) { + return KafkaRecordSender + .<ActivePowerRecord>builder( + bootstrapServers, + topic, + schemaRegistryUrl) + .keyAccessor(r -> r.getIdentifier()) + .timestampAccessor(r -> r.getTimestamp()) + .build(); + } +} diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanMessageGeneratorFactory.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanMessageGeneratorFactory.java deleted file mode 100644 index bd0b41d4e6e004d024ed2fd179eddcf6af50438f..0000000000000000000000000000000000000000 --- a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanMessageGeneratorFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -package theodolite.commons.workloadgeneration; - -import java.util.Properties; -import titan.ccp.model.records.ActivePowerRecord; - -/** - * A factory for creating {@link MessageGenerator}s that creates Titan {@link ActivePowerRecord}s - * and sends them via Kafka. - */ -public final class TitanMessageGeneratorFactory { - - private final RecordSender<ActivePowerRecord> recordSender; - - private TitanMessageGeneratorFactory(final RecordSender<ActivePowerRecord> recordSender) { - this.recordSender = recordSender; - } - - /** - * Create a {@link MessageGenerator} that generates Titan {@link ActivePowerRecord}s with a - * constant value. - */ - public MessageGenerator forConstantValue(final double value) { - return MessageGenerator.from( - sensor -> new ActivePowerRecord(sensor, System.currentTimeMillis(), value), - this.recordSender); - } - - /** - * Create a new TitanMessageGeneratorFactory for the given Kafka configuration. - */ - public static TitanMessageGeneratorFactory withKafkaConfig( - final String bootstrapServers, - final String topic, - final String schemaRegistryUrl) { - return withKafkaConfig(bootstrapServers, topic, schemaRegistryUrl, new Properties()); - } - - /** - * Create a new TitanMessageGeneratorFactory for the given Kafka configuration. - */ - public static TitanMessageGeneratorFactory withKafkaConfig( - final String bootstrapServers, - final String topic, - final String schemaRegistryUrl, - final Properties properties) { - final KafkaRecordSender<ActivePowerRecord> kafkaRecordSender = KafkaRecordSender - .<ActivePowerRecord>builder( - bootstrapServers, - topic, - schemaRegistryUrl) - .keyAccessor(r -> r.getIdentifier()) - .timestampAccessor(r -> r.getTimestamp()) - .build(); - return new TitanMessageGeneratorFactory(kafkaRecordSender); - } - -} diff --git a/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanRecordGeneratorFactory.java b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanRecordGeneratorFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..4e1c10071eff28d77514dbc121e30bead3f6fa74 --- /dev/null +++ b/theodolite-benchmarks/load-generator-commons/src/main/java/theodolite/commons/workloadgeneration/TitanRecordGeneratorFactory.java @@ -0,0 +1,21 @@ +package theodolite.commons.workloadgeneration; + +import titan.ccp.model.records.ActivePowerRecord; + +/** + * A factory for creating {@link RecordGenerator}s that creates Titan {@link ActivePowerRecord}s. + */ +public final class TitanRecordGeneratorFactory { + + + private TitanRecordGeneratorFactory() {} + + /** + * Create a {@link RecordGenerator} that generates Titan {@link ActivePowerRecord}s with a + * constant value. + */ + public static RecordGenerator<ActivePowerRecord> forConstantValue(final double value) { + return sensor -> new ActivePowerRecord(sensor, System.currentTimeMillis(), value); + } + +} diff --git a/theodolite/README.md b/theodolite/README.md index 26efe96b4756316971378be810f69f6138613958..60bd56d933d8955217120465c47e70b4b34585e1 100644 --- a/theodolite/README.md +++ b/theodolite/README.md @@ -2,21 +2,30 @@ This project uses Quarkus, the Supersonic Subatomic Java Framework. -If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . +If you want to learn more about Quarkus, please visit its website: <https://quarkus.io/> . ## Running the application in dev mode You can run your application in dev mode using: -```shell script +```sh ./gradlew quarkusDev ``` +### Hint for running with k3s (or k3d) + +You may need to add the following dependencies to the `build.gradle` file when running Theodolite with k3s. + +``` +implementation 'org.bouncycastle:bcprov-ext-jdk15on:1.68' +implementation 'org.bouncycastle:bcpkix-jdk15on:1.68' +``` + ## Packaging and running the application The application can be packaged using: -```shell script +```sh ./gradlew build ``` @@ -25,7 +34,7 @@ an _über-jar_ as the dependencies are copied into the `build/lib` directory. If you want to build an _über-jar_, execute the following command: -```shell script +```sh ./gradlew build -Dquarkus.package.type=uber-jar ``` @@ -33,92 +42,108 @@ The application is now runnable using `java -jar build/theodolite-1.0.0-SNAPSHOT ## Creating a native executable +It is recommended to use the native GraalVM images to create executable jars from Theodolite. For more information please visit the [Native Image guide](https://www.graalvm.org/reference-manual/native-image/). + You can create a native executable using: -```shell script +```sh ./gradlew build -Dquarkus.package.type=native ``` Or, if you don't have GraalVM installed, you can run the native executable build in a container using: -```shell script +```sh ./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true ``` You can then execute your native executable with: ```./build/theodolite-1.0.0-SNAPSHOT-runner``` -If you want to learn more about building native executables, please consult https://quarkus.io/guides/gradle-tooling. +If you want to learn more about building native executables, please consult <https://quarkus.io/guides/gradle-tooling>. ## Build docker images For the jvm version use: -```shell script +```sh ./gradlew build docker build -f src/main/docker/Dockerfile.jvm -t theodolite-jvm . ``` For the native image version use: -```shell script +```sh ./gradlew build -Dquarkus.package.type=native docker build -f src/main/docker/Dockerfile.native -t theodolite-native . ``` -## Execute docker images: +## Execute docker images Remember to set the environment variables first. Jvm version: -```shell script +```sh docker run -i --rm theodolite-jvm ``` Native image version: -```shell script +```sh docker run -i --rm theodolite-native ``` ## Environment variables -**Production:** (Docker-Container) +**Execution in Docker**: | Variables name | Default value |Usage | | -----------------------------|:----------------------------------:| ------------:| | `NAMESPACE` | `default` |Determines the namespace of the Theodolite will be executed in. Used in the KubernetesBenchmark| -| `THEODOLITE_EXECUTION` | `./config/BenchmarkExecution.yaml`|The complete path to the benchmarkExecution file. Used in the TheodoliteYamlExecutor. | -| `THEODOLITE_BENCHMARK_TYPE` | `./config/BenchmarkType.yaml` |The complete path to the benchmarkType file. Used in the TheodoliteYamlExecutor.| -| `THEODOLITE_APP_RESOURCES` | `./config` |The path under which the yamls for the resources for the subexperiments are found. Used in the KubernetesBenchmark| -| `MODE` | `yaml-executor` | Defines the mode of operation: either `yaml-executor` or `operator`| +| `THEODOLITE_EXECUTION` | `execution/execution.yaml` |The complete path to the benchmarkExecution file. Used in the TheodoliteYamlExecutor. | +| `THEODOLITE_BENCHMARK_TYPE` | `benchmark/benchmark.yaml` |The complete path to the benchmarkType file. Used in the TheodoliteYamlExecutor.| +| `THEODOLITE_APP_RESOURCES` | `./benchmark-resources` |The path under which the yamls for the resources for the subexperiments are found. Used in the KubernetesBenchmark| +| `MODE` | `standalone` |Defines the mode of operation: either `standalone` or `operator` -**Development:** (local via Intellij) +**Execution in IntelliJ**: When running Theodolite from within IntelliJ via -[Run Configurations](https://www.jetbrains.com/help/idea/work-with-gradle-tasks.html#gradle_run_config), set the * -Environment variables* field to: +[Run Configurations](https://www.jetbrains.com/help/idea/work-with-gradle-tasks.html#gradle_run_config), set the *Environment variables* field to: + +Set the following environment variables to run the example in the `standalone` mode within the IDE: +```sh +THEODOLITE_BENCHMARK=./../../../../examples/standalone/example-benchmark.yaml;THEODOLITE_EXECUTION=./../../../../examples/standalone/example-execution.yaml;THEODOLITE_APP_RESOURCES=./../../../../examples/resources; ``` -NAMESPACE=default;THEODOLITE_BENCHMARK=./../../../../config/BenchmarkType.yaml;THEODOLITE_APP_RESOURCES=./../../../../config;THEODOLITE_EXECUTION=./../../../../config/BenchmarkExecution.yaml;MODE=operator + +Alternative: + +``` sh +export THEODOLITE_BENCHMARK=./../../../../examples/standalone/example-benchmark.yaml +export THEODOLITE_APP_RESOURCES=./../../../../examples/resources; +export THEODOLITE_EXECUTION=./../../../../examples/standalone/example-execution.yaml +./gradlew quarkusDev +``` + +Set the following environment variables to run the example in the `operator` mode within the IDE: + +```sh +THEODOLITE_APP_RESOURCES=./../../../../examples/resources;MODE=operator ``` Alternative: ``` sh -export NAMESPACE=default -export THEODOLITE_BENCHMARK=./../../../../config/BenchmarkType.yaml -export THEODOLITE_APP_RESOURCES=./../../../../config -export THEODOLITE_EXECUTION=./../../../../config/BenchmarkExecution.yaml +export THEODOLITE_APP_RESOURCES=./../../../../examples/resources; export MODE=operator ./gradlew quarkusDev - ``` -#### Install Detekt Code analysis Plugin +Additionally, the benchmark and execution resources must be installed. + +### Install Detekt Code analysis Plugin -Install https://plugins.jetbrains.com/plugin/10761-detekt +Install <https://plugins.jetbrains.com/plugin/10761-detekt> - Install the plugin - Navigate to Settings/Preferences -> Tools -> Detekt @@ -127,7 +152,7 @@ Install https://plugins.jetbrains.com/plugin/10761-detekt -> detekt issues will be annotated on-the-fly while coding -**ingore Failures in build:** add +**ingore Failures in build**: add ```ignoreFailures = true``` diff --git a/theodolite/crd/crd-benchmark.yaml b/theodolite/crd/crd-benchmark.yaml index 7a861276a651af520ccec853b65cb57009a45cc5..7ab2e5f3b890a883f68dbbd36805f3791158f256 100644 --- a/theodolite/crd/crd-benchmark.yaml +++ b/theodolite/crd/crd-benchmark.yaml @@ -20,23 +20,124 @@ spec: properties: spec: type: object - required: ["appResource", "loadGenResource", "resourceTypes", "loadTypes", "kafkaConfig"] + required: ["sut", "loadGenerator", "resourceTypes", "loadTypes", "kafkaConfig"] properties: name: description: This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten. type: string - appResource: - description: A list of file names that reference Kubernetes resources that are deployed on the cluster for the system under test (SUT). - type: array - minItems: 1 - items: - type: string - loadGenResource: - description: A list of file names that reference Kubernetes resources that are deployed on the cluster for the load generator. - type: array - minItems: 1 - items: - type: string + default: "" + infrastructure: + description: (Optional) A list of file names that reference Kubernetes resources that are deployed on the cluster to create the required infrastructure. + type: object + default: {} + properties: + resources: + type: array + default: [] + items: + type: object + oneOf: + - required: [ configMap ] + - required: [ fileSystem ] + properties: + configMap: + description: The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap. + type: object + properties: + name: + description: The name of the configMap + type: string + files: + description: (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded. + type: array + items: + type: string + fileSystem: + description: The fileSystem resourceSet loads the Kubernetes manifests from the filesystem. + type: object + properties: + path: + description: The path to the folder which contains the Kubernetes manifests files. + type: string + files: + description: (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded. + type: array + items: + type: string + sut: + description: The appResourceSets specifies all Kubernetes resources required to start the sut. A resourceSet can be either a configMap resourceSet or a fileSystem resourceSet. + type: object + properties: + resources: + type: array + default: [ ] + items: + type: object + oneOf: + - required: [ configMap ] + - required: [ fileSystem ] + properties: + configMap: + description: The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap. + type: object + properties: + name: + description: The name of the configMap + type: string + files: + description: (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded. + type: array + items: + type: string + fileSystem: + description: The fileSystem resourceSet loads the Kubernetes manifests from the filesystem. + type: object + properties: + path: + description: The path to the folder which contains the Kubernetes manifests files. + type: string + files: + description: (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded. + type: array + items: + type: string + loadGenerator: + description: The loadGenResourceSets specifies all Kubernetes resources required to start the load generator. A resourceSet can be either a configMap resourceSet or a fileSystem resourceSet. + type: object + properties: + resources: + type: array + default: [] + items: + type: object + oneOf: + - required: [ configMap ] + - required: [ fileSystem ] + properties: + configMap: + description: The configMap resourceSet loads the Kubernetes manifests from an Kubernetes configMap. + type: object + properties: + name: + description: The name of the configMap + type: string + files: + description: (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded. + type: array + items: + type: string + fileSystem: + description: The fileSystem resourceSet loads the Kubernetes manifests from the filesystem. + type: object + properties: + path: + description: The path to the folder which contains the Kubernetes manifests files. + type: string + files: + description: (Optional) Specifies which files from the configMap should be loaded. If this field is not set, all files are loaded. + type: array + items: + type: string resourceTypes: description: A list of resource types that can be scaled for this `benchmark` resource. For each resource type the concrete values are defined in the `execution` object. type: array @@ -50,7 +151,6 @@ spec: type: string patchers: description: List of patchers used to scale this resource type. - examples: test test test type: array minItems: 1 items: @@ -136,10 +236,20 @@ spec: description: Determines if this topic should only be deleted after each experiement. For removeOnly topics the name can be a RegEx describing the topic. type: boolean default: false + status: + type: object + properties: + resourceSetsState: + description: The status of a Benchmark indicates whether all resources are available to start the benchmark or not. + type: string additionalPrinterColumns: - name: Age type: date jsonPath: .metadata.creationTimestamp + - name: STATUS + type: string + description: The status of a Benchmark indicates whether all resources are available to start the benchmark or not. + jsonPath: .status.resourceSetsState subresources: status: {} scope: Namespaced \ No newline at end of file diff --git a/theodolite/crd/crd-execution.yaml b/theodolite/crd/crd-execution.yaml index 47d0306f5150a8126f021c40bf3c4a4ce0e1abb1..d9cd41903bb2fdc18bd6640bdbe2eb764b2106ab 100644 --- a/theodolite/crd/crd-execution.yaml +++ b/theodolite/crd/crd-execution.yaml @@ -51,7 +51,7 @@ spec: description: The type of the resource. It must match one of the resource types specified in the referenced benchmark. type: string resourceValues: - descriptoin: List of resource values for the specified resource type. + description: List of resource values for the specified resource type. type: array items: type: integer diff --git a/theodolite/examples/operator/example-benchmark.yaml b/theodolite/examples/operator/example-benchmark.yaml index 91d9f8f1f7dfed31d9edcb59947af4e832ca2843..3452fff9c729d680890d6eafa685ce2f13b098d6 100644 --- a/theodolite/examples/operator/example-benchmark.yaml +++ b/theodolite/examples/operator/example-benchmark.yaml @@ -3,14 +3,19 @@ kind: benchmark metadata: name: uc1-kstreams 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" + sut: + resources: + - configMap: + name: "example-configmap" + files: + - "uc1-kstreams-deployment.yaml" + loadGenerator: + resources: + - configMap: + name: "example-configmap" + files: + - uc1-load-generator-service.yaml + - uc1-load-generator-deployment.yaml resourceTypes: - typeName: "Instances" patchers: diff --git a/theodolite/examples/operator/example-configmap.yaml b/theodolite/examples/operator/example-configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..210ce32d3fc0f75b9ffce874d1fa0a1ea9bdc3cd --- /dev/null +++ b/theodolite/examples/operator/example-configmap.yaml @@ -0,0 +1,87 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: example-configmap +data: + uc1-kstreams-deployment.yaml: |- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: titan-ccp-aggregation + spec: + selector: + matchLabels: + app: titan-ccp-aggregation + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-aggregation + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: uc-application + image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest + env: + - name: KAFKA_BOOTSTRAP_SERVERS + value: "theodolite-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://theodolite-cp-schema-registry:8081" + - name: JAVA_OPTS + value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=5555" + - name: COMMIT_INTERVAL_MS # Set as default for the applications + value: "100" + resources: + limits: + memory: 4Gi + cpu: 1000m + uc1-load-generator-deployment.yaml: | + apiVersion: apps/v1 + kind: Deployment + metadata: + name: titan-ccp-load-generator + spec: + selector: + matchLabels: + app: titan-ccp-load-generator + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-load-generator + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: workload-generator + image: ghcr.io/cau-se/theodolite-uc1-workload-generator:latest + ports: + - containerPort: 5701 + name: coordination + env: + - name: KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KUBERNETES_DNS_NAME + value: "titan-ccp-load-generator.$(KUBERNETES_NAMESPACE).svc.cluster.local" + - name: KAFKA_BOOTSTRAP_SERVERS + value: "theodolite-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://theodolite-cp-schema-registry:8081" + uc1-load-generator-service.yaml: | + apiVersion: v1 + kind: Service + metadata: + name: titan-ccp-load-generator + labels: + app: titan-ccp-load-generator + spec: + type: ClusterIP + clusterIP: None + selector: + app: titan-ccp-load-generator + ports: + - name: coordination + port: 5701 + targetPort: 5701 + protocol: TCP \ No newline at end of file diff --git a/theodolite/examples/resources/uc1-kstreams-deployment.yaml b/theodolite/examples/resources/uc1-kstreams-deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fdd1ff867ac83beb10856baec53569c88169232e --- /dev/null +++ b/theodolite/examples/resources/uc1-kstreams-deployment.yaml @@ -0,0 +1,34 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: titan-ccp-aggregation +spec: + selector: + matchLabels: + app: titan-ccp-aggregation + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-aggregation + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: uc-application + image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest + ports: + - containerPort: 5555 + name: jmx + env: + - name: KAFKA_BOOTSTRAP_SERVERS + value: "theodolite-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://theodolite-cp-schema-registry:8081" + - name: JAVA_OPTS + value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=5555" + - name: COMMIT_INTERVAL_MS # Set as default for the applications + value: "100" + resources: + limits: + memory: 4Gi + cpu: 1000m \ No newline at end of file diff --git a/theodolite/examples/resources/uc1-load-generator-deployment.yaml b/theodolite/examples/resources/uc1-load-generator-deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..9f9ccc6ae39407bb1f027e1e23cb152944b869e0 --- /dev/null +++ b/theodolite/examples/resources/uc1-load-generator-deployment.yaml @@ -0,0 +1,32 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: titan-ccp-load-generator +spec: + selector: + matchLabels: + app: titan-ccp-load-generator + replicas: 1 + template: + metadata: + labels: + app: titan-ccp-load-generator + spec: + terminationGracePeriodSeconds: 0 + containers: + - name: workload-generator + image: ghcr.io/cau-se/theodolite-uc1-workload-generator:latest + ports: + - containerPort: 5701 + name: coordination + env: + - name: KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KUBERNETES_DNS_NAME + value: "titan-ccp-load-generator.$(KUBERNETES_NAMESPACE).svc.cluster.local" + - name: KAFKA_BOOTSTRAP_SERVERS + value: "theodolite-cp-kafka:9092" + - name: SCHEMA_REGISTRY_URL + value: "http://theodolite-cp-schema-registry:8081" diff --git a/theodolite/examples/resources/uc1-load-generator-service.yaml b/theodolite/examples/resources/uc1-load-generator-service.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f8b26b3f6dece427f9c1ad4db94e351b042749b3 --- /dev/null +++ b/theodolite/examples/resources/uc1-load-generator-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: titan-ccp-load-generator + labels: + app: titan-ccp-load-generator +spec: + type: ClusterIP + clusterIP: None + selector: + app: titan-ccp-load-generator + ports: + - name: coordination + port: 5701 + targetPort: 5701 + protocol: TCP diff --git a/theodolite/examples/standalone/example-benchmark.yaml b/theodolite/examples/standalone/example-benchmark.yaml index 83edce93834ca9b8eef5606c1e5884ce40bdd7d8..0d5df81b163c1285f12971d08518dddf4b451d0f 100644 --- a/theodolite/examples/standalone/example-benchmark.yaml +++ b/theodolite/examples/standalone/example-benchmark.yaml @@ -1,12 +1,18 @@ 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" + infrastructure: [] + sut: + resources: + - configMap: + name: "example-configmap" + files: + - "uc1-kstreams-deployment.yaml" + loadGenerator: + resources: + - configMap: + name: "example-configmap" + files: + - uc1-load-generator-service.yaml + - uc1-load-generator-deployment.yaml resourceTypes: - typeName: "Instances" patchers: @@ -25,7 +31,7 @@ loadTypes: properties: loadGenMaxRecords: "15000" kafkaConfig: - bootstrapServer: "localhost:31290" + bootstrapServer: "theodolite-cp-kafka:9092" topics: - name: "input" numPartitions: 40 diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt b/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt index 05d021b1bcfb77fa8ffeb0522510d49e39ef501c..cf2fac7337d79c1c5daf2b0fac070200cf27f9a5 100644 --- a/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt +++ b/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt @@ -14,6 +14,9 @@ import theodolite.util.Resource @RegisterForReflection interface Benchmark { + fun setupInfrastructure() + fun teardownInfrastructure() + /** * Builds a Deployment that can be deployed. * @return a BenchmarkDeployment. diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkDeployment.kt b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkDeployment.kt index 92d3f7a012517895fc61531026e4ea4f3e3cfb50..fd01ecd986775ef704949743fef0d19f5492e9a6 100644 --- a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkDeployment.kt +++ b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkDeployment.kt @@ -7,8 +7,7 @@ package theodolite.benchmark interface BenchmarkDeployment { /** - * Setup a benchmark. This method is responsible for deploying the resources - * and organize the needed infrastructure. + * Setup a benchmark. This method is responsible for deploying the resources of a benchmark. */ fun setup() diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/ConfigMapResourceSet.kt b/theodolite/src/main/kotlin/theodolite/benchmark/ConfigMapResourceSet.kt new file mode 100644 index 0000000000000000000000000000000000000000..273a13170e77ae9e2f5f09869ebbc5cc06185715 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/ConfigMapResourceSet.kt @@ -0,0 +1,75 @@ +package theodolite.benchmark + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import io.fabric8.kubernetes.api.model.KubernetesResource +import io.fabric8.kubernetes.client.KubernetesClientException +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import io.quarkus.runtime.annotations.RegisterForReflection +import mu.KotlinLogging +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromString +import theodolite.util.DeploymentFailedException +import theodolite.util.YamlParserFromString +import java.lang.IllegalArgumentException +import java.lang.IllegalStateException + +private val logger = KotlinLogging.logger {} + +@RegisterForReflection +@JsonDeserialize +class ConfigMapResourceSet: ResourceSet, KubernetesResource { + lateinit var name: String + lateinit var files: List<String> // load all files, iff files is not set + + @OptIn(ExperimentalStdlibApi::class) + override fun getResourceSet(client: NamespacedKubernetesClient): Collection<Pair<String, KubernetesResource>> { + val loader = K8sResourceLoaderFromString(client) + var resources: Map<String, String> + + try { + resources = client + .configMaps() + .withName(name) + .get() + .data + .filter { it.key.endsWith(".yaml") } // consider only yaml files, e.g. ignore readme files + } catch (e: KubernetesClientException) { + throw DeploymentFailedException("can not find or read configmap: $name", e) + } catch (e: IllegalStateException) { + throw DeploymentFailedException("can not find configmap or data section is null $name", e) + } + + if (::files.isInitialized){ + resources = resources + .filter { files.contains(it.key) } + + if (resources.size != files.size) { + throw DeploymentFailedException("Could not find all specified Kubernetes manifests files") + } + } + + return try { + resources + .map { Pair( + getKind(resource = it.value), + it) } + .map { + Pair( + it.second.key, + loader.loadK8sResource(it.first, it.second.value)) } + } catch (e: IllegalArgumentException) { + throw DeploymentFailedException("Can not creat resource set from specified configmap", e) + } + + } + + private fun getKind(resource: String): String { + val parser = YamlParserFromString() + val resourceAsMap = parser.parse(resource, HashMap<String, String>()::class.java) + + return try { + resourceAsMap?.get("kind") !! + } catch (e: NullPointerException) { + throw DeploymentFailedException( "Could not find field kind of Kubernetes resource: ${resourceAsMap?.get("name")}", e) + } + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/FileSystemResourceSet.kt b/theodolite/src/main/kotlin/theodolite/benchmark/FileSystemResourceSet.kt new file mode 100644 index 0000000000000000000000000000000000000000..92df1bec3cd6f21b1f830e73b466f70e37a9f4c8 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/FileSystemResourceSet.kt @@ -0,0 +1,66 @@ +package theodolite.benchmark + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import io.fabric8.kubernetes.api.model.KubernetesResource +import io.fabric8.kubernetes.client.DefaultKubernetesClient +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import io.quarkus.runtime.annotations.RegisterForReflection +import mu.KotlinLogging +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile +import theodolite.util.DeploymentFailedException +import theodolite.util.YamlParserFromFile +import java.io.File +import java.io.FileNotFoundException +import java.lang.IllegalArgumentException + +private val logger = KotlinLogging.logger {} + +@RegisterForReflection +@JsonDeserialize +class FileSystemResourceSet: ResourceSet, KubernetesResource { + lateinit var path: String + lateinit var files: List<String> + + override fun getResourceSet(client: NamespacedKubernetesClient): Collection<Pair<String, KubernetesResource>> { + + //if files is set ... + if(::files.isInitialized){ + return files + .map { loadSingleResource(resourceURL = it, client = client) } + } + + return try { + File(path) + .list() !! + .filter { it.endsWith(".yaml") } // consider only yaml files, e.g. ignore readme files + .map { + loadSingleResource(resourceURL = it, client = client) + } + } catch (e: NullPointerException) { + throw DeploymentFailedException("Could not load files located in $path", e) + } + } + + private fun loadSingleResource(resourceURL: String, client: NamespacedKubernetesClient): Pair<String, KubernetesResource> { + val parser = YamlParserFromFile() + val loader = K8sResourceLoaderFromFile(client) + val resourcePath = "$path/$resourceURL" + lateinit var kind: String + + try { + kind = parser.parse(resourcePath, HashMap<String, String>()::class.java)?.get("kind")!! + } catch (e: NullPointerException) { + throw DeploymentFailedException("Can not get Kind from resource $resourcePath", e) + } catch (e: FileNotFoundException){ + throw DeploymentFailedException("File $resourcePath not found", e) + + } + + return try { + val k8sResource = loader.loadK8sResource(kind, resourcePath) + Pair(resourceURL, k8sResource) + } catch (e: IllegalArgumentException) { + throw DeploymentFailedException("Could not load resource: $resourcePath", e) + } + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt index b9a2fc7f18b92664b4d93b11755280a9e18b170d..0b81f8701f92a95662efef6e0d58839c9a2f6f3b 100644 --- a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt +++ b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt @@ -1,14 +1,18 @@ package theodolite.benchmark +import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.annotation.JsonDeserialize import io.fabric8.kubernetes.api.model.KubernetesResource import io.fabric8.kubernetes.client.DefaultKubernetesClient +import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.quarkus.runtime.annotations.RegisterForReflection import mu.KotlinLogging -import theodolite.k8s.K8sResourceLoader +import theodolite.k8s.K8sManager +import theodolite.k8s.resourceLoader.K8sResourceLoader import theodolite.patcher.PatcherFactory import theodolite.util.* + private val logger = KotlinLogging.logger {} private var DEFAULT_NAMESPACE = "default" @@ -34,34 +38,40 @@ private var DEFAULT_THEODOLITE_APP_RESOURCES = "./benchmark-resources" @RegisterForReflection 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 + lateinit var infrastructure: Resources + lateinit var sut: Resources + lateinit var loadGenerator: Resources var namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE + @Transient + private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace) /** * Loads [KubernetesResource]s. - * It first loads them via the [YamlParser] to check for their concrete type and afterwards initializes them using + * It first loads them via the [YamlParserFromFile] to check for their concrete type and afterwards initializes them using * the [K8sResourceLoader] */ - private fun loadKubernetesResources(resources: List<String>): List<Pair<String, KubernetesResource>> { - val path = System.getenv("THEODOLITE_APP_RESOURCES") ?: DEFAULT_THEODOLITE_APP_RESOURCES - logger.info { "Using $path as resource path." } + fun loadKubernetesResources(resourceSet: List<ResourceSets>): Collection<Pair<String, KubernetesResource>> { + return resourceSet.flatMap { it.loadResourceSet(this.client) } + } - val parser = YamlParser() - val loader = K8sResourceLoader(DefaultKubernetesClient()) - return resources - .map { resource -> - val resourcePath = "$path/$resource" - val kind = parser.parse(resourcePath, HashMap<String, String>()::class.java)?.get("kind")!! - val k8sResource = loader.loadK8sResource(kind, resourcePath) - Pair(resource, k8sResource) - } + override fun setupInfrastructure() { + val kubernetesManager = K8sManager(this.client) + loadKubernetesResources(this.infrastructure.resources) + .map{it.second} + .forEach { kubernetesManager.deploy(it) } } + override fun teardownInfrastructure() { + val kubernetesManager = K8sManager(this.client) + loadKubernetesResources(this.infrastructure.resources) + .map{it.second} + .forEach { kubernetesManager.remove(it) } + } + /** * Builds a deployment. * First loads all required resources and then patches them to the concrete load and resources for the experiment. @@ -80,8 +90,8 @@ class KubernetesBenchmark : KubernetesResource, Benchmark { ): BenchmarkDeployment { logger.info { "Using $namespace as namespace." } - val appResources = loadKubernetesResources(this.appResource) - val loadGenResources = loadKubernetesResources(this.loadGenResource) + val appResources = loadKubernetesResources(this.sut.resources) + val loadGenResources = loadKubernetesResources(this.loadGenerator.resources) val patcherFactory = PatcherFactory() @@ -106,7 +116,7 @@ class KubernetesBenchmark : KubernetesResource, Benchmark { afterTeardownDelay = afterTeardownDelay, kafkaConfig = hashMapOf("bootstrap.servers" to kafkaConfig.bootstrapServer), topics = kafkaConfig.topics, - client = DefaultKubernetesClient().inNamespace(namespace) + client = this.client ) } } diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSet.kt b/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSet.kt new file mode 100644 index 0000000000000000000000000000000000000000..19fc85845ae99c7a5e4f7369db4b6cd383c3131b --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSet.kt @@ -0,0 +1,13 @@ +package theodolite.benchmark + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import io.fabric8.kubernetes.api.model.KubernetesResource +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import io.quarkus.runtime.annotations.RegisterForReflection + +@RegisterForReflection +@JsonDeserialize +interface ResourceSet: KubernetesResource { + + fun getResourceSet(client: NamespacedKubernetesClient): Collection<Pair<String, KubernetesResource>> +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSets.kt b/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSets.kt new file mode 100644 index 0000000000000000000000000000000000000000..a4fe443e7f304c411792ee06c32592ba3c9e692a --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSets.kt @@ -0,0 +1,32 @@ +package theodolite.benchmark + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import io.fabric8.kubernetes.api.model.KubernetesResource +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import io.quarkus.runtime.annotations.RegisterForReflection +import mu.KotlinLogging +import theodolite.util.DeploymentFailedException + +@JsonDeserialize +@RegisterForReflection +class ResourceSets: KubernetesResource { + @JsonProperty("configMap") + @JsonInclude(JsonInclude.Include.NON_NULL) + var configMap: ConfigMapResourceSet? = null + + @JsonProperty("fileSystem") + @JsonInclude(JsonInclude.Include.NON_NULL) + var fileSystem: FileSystemResourceSet? = null + + fun loadResourceSet(client: NamespacedKubernetesClient): Collection<Pair<String, KubernetesResource>> { + return if (::configMap != null) { + configMap?.getResourceSet(client= client) !! + } else if (::fileSystem != null) { + fileSystem?.getResourceSet(client= client ) !! + } else { + throw DeploymentFailedException("could not load resourceSet.") + } + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/Resources.kt b/theodolite/src/main/kotlin/theodolite/benchmark/Resources.kt new file mode 100644 index 0000000000000000000000000000000000000000..0187735b8fd273419874942cb7ed68797732c84c --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/Resources.kt @@ -0,0 +1,13 @@ +package theodolite.benchmark + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import io.quarkus.runtime.annotations.RegisterForReflection + +@JsonDeserialize +@RegisterForReflection +class Resources { + + lateinit var resources: List<ResourceSets> + +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt index 777ea1c0ed43ac3af244dc0aaf770c69c11718cf..281c68e318784ee8206473cd014f814b3f5152a9 100644 --- a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt +++ b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt @@ -2,6 +2,7 @@ package theodolite.evaluation import mu.KotlinLogging import theodolite.benchmark.BenchmarkExecution +import theodolite.util.EvaluationFailedException import theodolite.util.IOHandler import theodolite.util.LoadDimension import theodolite.util.Resource @@ -12,7 +13,6 @@ import java.util.* import java.util.regex.Pattern private val logger = KotlinLogging.logger {} -private val RECORD_LAG_QUERY = "sum by(group)(kafka_consumergroup_group_lag >= 0)" /** * Contains the analysis. Fetches a metric from Prometheus, documents it, and evaluates it. @@ -37,7 +37,7 @@ class AnalysisExecutor( * @return true if the experiment succeeded. */ fun analyze(load: LoadDimension, res: Resource, executionIntervals: List<Pair<Instant, Instant>>): Boolean { - var result = false + var result: Boolean var repetitionCounter = 1 try { @@ -50,7 +50,7 @@ class AnalysisExecutor( fetcher.fetchMetric( start = interval.first, end = interval.second, - query = RECORD_LAG_QUERY + query = SloConfigHandler.getQueryString(sloType = slo.sloType) ) } @@ -58,7 +58,7 @@ class AnalysisExecutor( ioHandler.writeToCSVFile( fileURL = "${fileURL}_${repetitionCounter++}", data = data.getResultAsList(), - columns = listOf("group", "timestamp", "value") + columns = listOf("labels", "timestamp", "value") ) } @@ -71,8 +71,7 @@ class AnalysisExecutor( result = sloChecker.evaluate(prometheusData) } catch (e: Exception) { - // TODO(throw exception in order to make it possible to mark an experiment as unsuccessfully) - logger.error { "Evaluation failed for resource '${res.get()}' and load '${load.get()}'. Error: $e" } + throw EvaluationFailedException("Evaluation failed for resource '${res.get()}' and load '${load.get()} ", e) } return result } diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt b/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt index 448a2a05f8dbeb1aef153895360bfb40e7275224..d646286b70bc5880df1f603afdc2bda22bcc3259 100644 --- a/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt +++ b/theodolite/src/main/kotlin/theodolite/evaluation/ExternalSloChecker.kt @@ -36,13 +36,12 @@ class ExternalSloChecker( */ override fun evaluate(fetchedData: List<PrometheusResponse>): Boolean { var counter = 0 - val data = Gson().toJson( - mapOf( - "total_lags" to fetchedData.map { it.data?.result }, - "threshold" to threshold, - "warmup" to warmup - ) - ) + val data = SloJson.Builder() + .results(fetchedData.map { it.data?.result }) + .addMetadata("threshold", threshold) + .addMetadata( "warmup", warmup) + .build() + .toJson() while (counter < RETRIES) { val result = post(externalSlopeURL, data = data, timeout = TIMEOUT) diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/MetricFetcher.kt b/theodolite/src/main/kotlin/theodolite/evaluation/MetricFetcher.kt index 833d7d1e16c2fbc91b58817b319a7d02af7f5b2b..e54d79fe0f95b9f6079bd4295a74e81250b73a90 100644 --- a/theodolite/src/main/kotlin/theodolite/evaluation/MetricFetcher.kt +++ b/theodolite/src/main/kotlin/theodolite/evaluation/MetricFetcher.kt @@ -53,8 +53,7 @@ class MetricFetcher(private val prometheusURL: String, private val offset: Durat } else { val values = parseValues(response) if (values.data?.result.isNullOrEmpty()) { - logger.error { "Empty query result: $values between $start and $end for query $query." } - throw NoSuchFieldException() + throw NoSuchFieldException("Empty query result: $values between $start and $end for query $query.") } return parseValues(response) } diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt index 93e8e6180f5a99486e500af022869d896067d128..64f9110cd931feef41dc65f88d6623e82f4e03a2 100644 --- a/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt +++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt @@ -43,22 +43,23 @@ class SloCheckerFactory { properties: MutableMap<String, String>, load: LoadDimension ): SloChecker { - return when (sloType) { - "lag trend" -> ExternalSloChecker( + return when (sloType.toLowerCase()) { + SloTypes.LAG_TREND.value, SloTypes.DROPPED_RECORDS.value -> ExternalSloChecker( externalSlopeURL = properties["externalSloUrl"] ?: throw IllegalArgumentException("externalSloUrl expected"), threshold = properties["threshold"]?.toInt() ?: throw IllegalArgumentException("threshold expected"), warmup = properties["warmup"]?.toInt() ?: throw IllegalArgumentException("warmup expected") ) - "lag trend ratio" -> { - var thresholdRatio = + + SloTypes.LAG_TREND_RATIO.value, SloTypes.DROPPED_RECORDS_RATIO.value -> { + val thresholdRatio = properties["ratio"]?.toDouble() ?: throw IllegalArgumentException("ratio for threshold expected") if (thresholdRatio < 0.0) { throw IllegalArgumentException("Threshold ratio needs to be an Double greater or equal 0.0") } // cast to int, as rounding is not really necessary - var threshold = (load.get() * thresholdRatio).toInt() + val threshold = (load.get() * thresholdRatio).toInt() ExternalSloChecker( externalSlopeURL = properties["externalSloUrl"] diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloConfigHandler.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloConfigHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..93929218c822030ff065dafb19cce1fbaa69a179 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloConfigHandler.kt @@ -0,0 +1,20 @@ +package theodolite.evaluation + +import theodolite.util.InvalidPatcherConfigurationException +import javax.enterprise.context.ApplicationScoped + +private const val CONSUMER_LAG_QUERY = "sum by(group)(kafka_consumergroup_group_lag >= 0)" +private const val DROPPED_RECORDS_QUERY = "sum by(job) (kafka_streams_stream_task_metrics_dropped_records_total>=0)" + +@ApplicationScoped +class SloConfigHandler() { + companion object { + fun getQueryString(sloType: String): String { + return when (sloType.toLowerCase()) { + SloTypes.LAG_TREND.value, SloTypes.LAG_TREND_RATIO.value -> CONSUMER_LAG_QUERY + SloTypes.DROPPED_RECORDS.value, SloTypes.DROPPED_RECORDS_RATIO.value -> DROPPED_RECORDS_QUERY + else -> throw InvalidPatcherConfigurationException("Could not find Prometheus query string for slo type $sloType") + } + } + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloJson.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloJson.kt new file mode 100644 index 0000000000000000000000000000000000000000..fc9fe17b255dbb5ae68881538d8d2a50a191edb1 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloJson.kt @@ -0,0 +1,63 @@ +package theodolite.evaluation + +import com.google.gson.Gson +import theodolite.util.PromResult + +class SloJson private constructor( + val results: List<List<PromResult>?>? = null, + var metadata: MutableMap<String, Any>? = null +) { + + data class Builder( + var results:List<List<PromResult>?>? = null, + var metadata: MutableMap<String, Any>? = null + ) { + + /** + * Set the results + * + * @param results list of prometheus results + */ + fun results(results: List<List<PromResult>?>) = apply { this.results = results } + + /** + * Add metadata as key value pairs + * + * @param key key of the metadata to be added + * @param value value of the metadata to be added + */ + fun addMetadata(key: String, value: String) = apply { + if (this.metadata.isNullOrEmpty()) { + this.metadata = mutableMapOf(key to value) + } else { + this.metadata!![key] = value + } + } + + /** + * Add metadata as key value pairs + * + * @param key key of the metadata to be added + * @param value value of the metadata to be added + */ + fun addMetadata(key: String, value: Int) = apply { + if (this.metadata.isNullOrEmpty()) { + this.metadata = mutableMapOf(key to value) + } else { + this.metadata!![key] = value + } + } + + fun build() = SloJson( + results = results, + metadata = metadata + ) + } + + fun toJson(): String { + return Gson().toJson(mapOf( + "results" to this.results, + "metadata" to this.metadata + )) + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloTypes.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloTypes.kt new file mode 100644 index 0000000000000000000000000000000000000000..ac9de35861b0bd9c012bfb0b8cfcb2e1aa5aed68 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloTypes.kt @@ -0,0 +1,10 @@ +package theodolite.evaluation + +enum class SloTypes(val value: String) { + LAG_TREND("lag trend"), + LAG_TREND_RATIO("lag trend ratio"), + DROPPED_RECORDS("dropped records"), + DROPPED_RECORDS_RATIO("dropped records ratio") + + +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt index e7b511d8c83b5abccece1204aad2a4a9ecfdfd26..3238f447be06ce6486bb7f6ca1758700f36ba558 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt @@ -25,11 +25,12 @@ abstract class BenchmarkExecutor( val results: Results, val executionDuration: Duration, val configurationOverrides: List<ConfigurationOverride?>, - val slo: BenchmarkExecution.Slo, + val slos: List<BenchmarkExecution.Slo>, val repetitions: Int, val executionId: Int, val loadGenerationDelay: Long, - val afterTeardownDelay: Long + val afterTeardownDelay: Long, + val executionName: String ) { var run: AtomicBoolean = AtomicBoolean(true) diff --git a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt index c54d1878d4957a0b8ec6a8fdfb18ec6342d7bfc1..2e938be3a6e503a5e7e3f94c18a9454e173db5b0 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt @@ -5,10 +5,8 @@ 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.execution.operator.EventCreator +import theodolite.util.* import java.time.Duration import java.time.Instant @@ -20,29 +18,34 @@ class BenchmarkExecutorImpl( results: Results, executionDuration: Duration, configurationOverrides: List<ConfigurationOverride?>, - slo: BenchmarkExecution.Slo, + slos: List<BenchmarkExecution.Slo>, repetitions: Int, executionId: Int, loadGenerationDelay: Long, - afterTeardownDelay: Long + afterTeardownDelay: Long, + executionName: String ) : BenchmarkExecutor( benchmark, results, executionDuration, configurationOverrides, - slo, + slos, repetitions, executionId, loadGenerationDelay, - afterTeardownDelay + afterTeardownDelay, + executionName ) { + private val eventCreator = EventCreator() + private val mode = Configuration.EXECUTION_MODE + override fun runExperiment(load: LoadDimension, res: Resource): Boolean { var result = false val executionIntervals: MutableList<Pair<Instant, Instant>> = ArrayList() for (i in 1.rangeTo(repetitions)) { - logger.info { "Run repetition $i/$repetitions" } if (this.run.get()) { + logger.info { "Run repetition $i/$repetitions" } executionIntervals.add(runSingleExperiment(load, res)) } else { break @@ -53,14 +56,23 @@ class BenchmarkExecutorImpl( * Analyse the experiment, if [run] is true, otherwise the experiment was canceled by the user. */ if (this.run.get()) { - result = AnalysisExecutor(slo = slo, executionId = executionId) - .analyze( - load = load, - res = res, - executionIntervals = executionIntervals - ) + val experimentResults = slos.map { + AnalysisExecutor(slo = it, executionId = executionId) + .analyze( + load = load, + res = res, + executionIntervals = executionIntervals + ) + } + + result = (false !in experimentResults) this.results.setResult(Pair(load, res), result) } + + if(!this.run.get()) { + throw ExecutionFailedException("The execution was interrupted") + } + return result } @@ -73,22 +85,49 @@ class BenchmarkExecutorImpl( this.afterTeardownDelay ) val from = Instant.now() - // TODO(restructure try catch in order to throw exceptions if there are significant problems by running a experiment) + try { benchmarkDeployment.setup() this.waitAndLog() + if (mode == ExecutionModes.OPERATOR.value) { + eventCreator.createEvent( + executionName = executionName, + type = "NORMAL", + reason = "Start experiment", + message = "load: ${load.get()}, resources: ${res.get()}") + } } catch (e: Exception) { - logger.error { "Error while setup experiment." } - logger.error { "Error is: $e" } this.run.set(false) + + if (mode == ExecutionModes.OPERATOR.value) { + eventCreator.createEvent( + executionName = executionName, + type = "WARNING", + reason = "Start experiment failed", + message = "load: ${load.get()}, resources: ${res.get()}") + } + throw ExecutionFailedException("Error during setup the experiment", e) } val to = Instant.now() try { benchmarkDeployment.teardown() + if (mode == ExecutionModes.OPERATOR.value) { + eventCreator.createEvent( + executionName = executionName, + type = "NORMAL", + reason = "Stop experiment", + message = "Teardown complete") + } } catch (e: Exception) { - logger.warn { "Error while tearing down the benchmark deployment." } - logger.debug { "Teardown failed, caused by: $e" } + if (mode == ExecutionModes.OPERATOR.value) { + eventCreator.createEvent( + executionName = executionName, + type = "WARNING", + reason = "Stop experiment failed", + message = "Teardown failed: ${e.message}") + } + throw ExecutionFailedException("Error during teardown the experiment", e) } return Pair(from, to) } -} +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/execution/ExecutionModes.kt b/theodolite/src/main/kotlin/theodolite/execution/ExecutionModes.kt new file mode 100644 index 0000000000000000000000000000000000000000..bf947be01b534fd000d3967f0b72ef25978d4110 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/execution/ExecutionModes.kt @@ -0,0 +1,7 @@ +package theodolite.execution + +enum class ExecutionModes(val value: String) { + OPERATOR("operator"), + YAML_EXECUTOR("yaml-executor"), + STANDALONE("standalone") +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/execution/Main.kt b/theodolite/src/main/kotlin/theodolite/execution/Main.kt index 7d5fca859422a194e81468d9766a9e7ba29fb998..11f696ddd739e987e92ecec724390948714d898b 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/Main.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/Main.kt @@ -3,6 +3,7 @@ package theodolite.execution import io.quarkus.runtime.annotations.QuarkusMain import mu.KotlinLogging import theodolite.execution.operator.TheodoliteOperator +import theodolite.util.Configuration import kotlin.system.exitProcess private val logger = KotlinLogging.logger {} @@ -13,13 +14,12 @@ object Main { @JvmStatic fun main(args: Array<String>) { - val mode = System.getenv("MODE") ?: "standalone" + val mode = Configuration.EXECUTION_MODE logger.info { "Start Theodolite with mode $mode" } - when (mode) { - "standalone" -> TheodoliteStandalone().start() - "yaml-executor" -> TheodoliteStandalone().start() // TODO remove (#209) - "operator" -> TheodoliteOperator().start() + when (mode.toLowerCase()) { + ExecutionModes.STANDALONE.value, ExecutionModes.YAML_EXECUTOR.value -> TheodoliteStandalone().start() // TODO remove standalone (#209) + ExecutionModes.OPERATOR.value -> TheodoliteOperator().start() else -> { logger.error { "MODE $mode not found" } exitProcess(1) diff --git a/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt b/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt index e795ada3e3bcb2dba19f1e088f426f38a824f4a7..6dedc94af864269d7d15929c69ec54aa384fc8e3 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt @@ -34,16 +34,15 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b afterTeardownDelay = 5L ) deployment.teardown() + logger.info { + "Finished teardown of all benchmark resources." + } } catch (e: Exception) { - // TODO(throw exception in order to make it possible to mark an experiment as unsuccessfully) logger.warn { "Could not delete all specified resources from Kubernetes. " + "This could be the case, if not all resources are deployed and running." } } - logger.info { - "Finished teardown of all benchmark resources." - } } } diff --git a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt index addf30acde31ee8e3e53c20a5e2b57a03587d08e..315d1cf1afe7fd2ffbfc1c437d725d4dff29f637 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt @@ -61,11 +61,12 @@ class TheodoliteExecutor( results = results, executionDuration = executionDuration, configurationOverrides = config.configOverrides, - slo = config.slos[0], + slos = config.slos, repetitions = config.execution.repetitions, executionId = config.executionId, loadGenerationDelay = config.execution.loadGenerationDelay, - afterTeardownDelay = config.execution.afterTeardownDelay + afterTeardownDelay = config.execution.afterTeardownDelay, + executionName = config.name ) if (config.load.loadValues != config.load.loadValues.sorted()) { @@ -112,6 +113,8 @@ class TheodoliteExecutor( * execution and benchmark objects. */ fun run() { + kubernetesBenchmark.setupInfrastructure() + val ioHandler = IOHandler() val resultsFolder = ioHandler.getResultFolderURL() this.config.executionId = getAndIncrementExecutionID(resultsFolder + "expID.txt") @@ -123,15 +126,19 @@ class TheodoliteExecutor( val config = buildConfig() // execute benchmarks for each load - for (load in config.loads) { - if (executor.run.get()) { - config.compositeStrategy.findSuitableResource(load, config.resources) + try { + for (load in config.loads) { + if (executor.run.get()) { + config.compositeStrategy.findSuitableResource(load, config.resources) + } } + } finally { + ioHandler.writeToJSONFile( + config.compositeStrategy.benchmarkExecutor.results, + "${resultsFolder}exp${this.config.executionId}-result" + ) } - ioHandler.writeToJSONFile( - config.compositeStrategy.benchmarkExecutor.results, - "${resultsFolder}exp${this.config.executionId}-result" - ) + kubernetesBenchmark.teardownInfrastructure() } private fun getAndIncrementExecutionID(fileURL: String): Int { diff --git a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteStandalone.kt b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteStandalone.kt index 76fd7f707a3e190ff6c61052ae4b5aaf50459418..1bbf3e01f461a19dbe588aedd41be63b84c86162 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteStandalone.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteStandalone.kt @@ -3,7 +3,9 @@ package theodolite.execution import mu.KotlinLogging import theodolite.benchmark.BenchmarkExecution import theodolite.benchmark.KubernetesBenchmark -import theodolite.util.YamlParser +import theodolite.util.YamlParserFromFile +import theodolite.util.EvaluationFailedException +import theodolite.util.ExecutionFailedException import kotlin.concurrent.thread import kotlin.system.exitProcess @@ -26,7 +28,7 @@ private val logger = KotlinLogging.logger {} * @constructor Create empty Theodolite yaml executor */ class TheodoliteStandalone { - private val parser = YamlParser() + private val parser = YamlParserFromFile() fun start() { logger.info { "Theodolite started" } @@ -49,8 +51,14 @@ class TheodoliteStandalone { val shutdown = thread(start = false) { Shutdown(benchmarkExecution, benchmark).run() } Runtime.getRuntime().addShutdownHook(shutdown) - val executor = TheodoliteExecutor(benchmarkExecution, benchmark) - executor.run() + try { + TheodoliteExecutor(benchmarkExecution, benchmark).run() + } catch (e: EvaluationFailedException) { + logger.error { "Evaluation failed with error: ${e.message}" } + }catch (e: ExecutionFailedException) { + logger.error { "Execution failed with error: ${e.message}" } + } + logger.info { "Theodolite finished" } Runtime.getRuntime().removeShutdownHook(shutdown) exitProcess(0) diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt index 9d7436526f18081c7130870956d8a5eea5fc8997..0b5d6040bdea1316f8fb55bcc3f204c5443f6eee 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/AbstractStateHandler.kt @@ -4,10 +4,13 @@ import io.fabric8.kubernetes.api.model.HasMetadata import io.fabric8.kubernetes.api.model.KubernetesResourceList import io.fabric8.kubernetes.api.model.Namespaced import io.fabric8.kubernetes.client.CustomResource +import io.fabric8.kubernetes.client.KubernetesClientException import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.fabric8.kubernetes.client.dsl.MixedOperation import io.fabric8.kubernetes.client.dsl.Resource +import mu.KotlinLogging import java.lang.Thread.sleep +private val logger = KotlinLogging.logger {} abstract class AbstractStateHandler<T, L, D>( private val client: NamespacedKubernetesClient, @@ -20,11 +23,15 @@ abstract class AbstractStateHandler<T, L, D>( @Synchronized override fun setState(resourceName: String, f: (T) -> T?) { - this.crdClient - .list().items - .filter { it.metadata.name == resourceName } - .map { customResource -> f(customResource) } - .forEach { this.crdClient.updateStatus(it) } + try { + this.crdClient + .list().items + .filter { it.metadata.name == resourceName } + .map { customResource -> f(customResource) } + .forEach { this.crdClient.updateStatus(it) } + } catch (e: KubernetesClientException) { + logger.warn { "Status cannot be set for resource $resourceName" } + } } @Synchronized diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/BenchmarkStateHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/BenchmarkStateHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..adca2a8b7fdb9b3e610f15e57c011679869df14c --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/BenchmarkStateHandler.kt @@ -0,0 +1,28 @@ +package theodolite.execution.operator + +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import theodolite.model.crd.* + +class BenchmarkStateHandler(val client: NamespacedKubernetesClient) : + AbstractStateHandler<BenchmarkCRD, KubernetesBenchmarkList, ExecutionStatus>( + client = client, + crd = BenchmarkCRD::class.java, + crdList = KubernetesBenchmarkList::class.java + ) { + + private fun getBenchmarkResourceState() = { cr: BenchmarkCRD -> cr.status.resourceSetsState } + + fun setResourceSetState(resourceName: String, status: BenchmarkStates): Boolean { + setState(resourceName) { cr -> cr.status.resourceSetsState = status.value; cr } + return blockUntilStateIsSet(resourceName, status.value, getBenchmarkResourceState()) + } + + fun getResourceSetState(resourceName: String): ExecutionStates { + val status = this.getState(resourceName, getBenchmarkResourceState()) + return if (status.isNullOrBlank()) { + ExecutionStates.NO_STATE + } else { + ExecutionStates.values().first { it.value == status } + } + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt index c3a2b7b25ed71e797c45d8b497bad6cad15e21e8..efca98f8bf72024daa0367c6c57574f0644872e4 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt @@ -41,7 +41,7 @@ class ClusterSetup( .list() .items .asSequence() - .filter { it.status.executionState == States.RUNNING.value } + .filter { it.status.executionState == ExecutionStates.RUNNING.value } .forEach { execution -> val benchmark = benchmarkCRDClient .inNamespace(client.namespace) @@ -54,11 +54,8 @@ class ClusterSetup( 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." - } - throw IllegalStateException("Cluster state is invalid, required Benchmark for running execution not found.") + throw IllegalStateException("Execution with state ${ExecutionStates.RUNNING.value} was found, but no corresponding benchmark. " + + "Could not initialize cluster.") } } } diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/EventCreator.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/EventCreator.kt new file mode 100644 index 0000000000000000000000000000000000000000..fab098ebd5fe765a455d787ddb7fcbfbb6c9ffc7 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/EventCreator.kt @@ -0,0 +1,60 @@ +package theodolite.execution.operator + +import io.fabric8.kubernetes.api.model.EventBuilder +import io.fabric8.kubernetes.api.model.EventSource +import io.fabric8.kubernetes.api.model.ObjectReference +import io.fabric8.kubernetes.client.DefaultKubernetesClient +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import mu.KotlinLogging +import theodolite.util.Configuration +import java.time.Instant +import java.util.* +import kotlin.NoSuchElementException +private val logger = KotlinLogging.logger {} + +class EventCreator { + val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(Configuration.NAMESPACE) + + fun createEvent(executionName: String, type: String, message: String, reason: String) { + val uuid = UUID.randomUUID().toString() + try { + val objectRef = buildObjectReference(executionName) + val event = EventBuilder() + .withNewMetadata() + .withName(uuid) + .endMetadata() + .withMessage(message) + .withReason(reason) + .withType(type) + .withFirstTimestamp(Instant.now().toString()) // TODO change datetime format + .build() + + val source = EventSource() + source.component = Configuration.COMPONENT_NAME + event.source = source + + event.involvedObject = objectRef + client.v1().events().inNamespace(Configuration.NAMESPACE).createOrReplace(event) + } catch (e: NoSuchElementException) { + logger.warn {"Could not create event: type: $type, message: $message, reason: $reason, no corresponding execution found."} + } + } + + private fun buildObjectReference(executionName: String): ObjectReference { + val exec = TheodoliteOperator() + .getExecutionClient(client = client) + .list() + .items + .first{it.metadata.name == executionName} + + val objectRef = ObjectReference() + objectRef.apiVersion = exec.apiVersion + objectRef.kind = exec.kind + objectRef.uid = exec.metadata.uid + objectRef.name = exec.metadata.name + objectRef.namespace = exec.metadata.namespace + objectRef.resourceVersion = exec.metadata.resourceVersion + + return objectRef + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt index 1209195ee09cebe382f010f38e955dea1c860cd1..16c4ea98ba614bb3dcdd7d9f486f4e65ae70d380 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionEventHandler.kt @@ -33,9 +33,9 @@ class ExecutionHandler( logger.info { "Add execution ${execution.metadata.name}" } execution.spec.name = execution.metadata.name when (this.stateHandler.getExecutionState(execution.metadata.name)) { - States.NO_STATE -> this.stateHandler.setExecutionState(execution.spec.name, States.PENDING) - States.RUNNING -> { - this.stateHandler.setExecutionState(execution.spec.name, States.RESTART) + ExecutionStates.NO_STATE -> this.stateHandler.setExecutionState(execution.spec.name, ExecutionStates.PENDING) + ExecutionStates.RUNNING -> { + this.stateHandler.setExecutionState(execution.spec.name, ExecutionStates.RESTART) if (this.controller.isExecutionRunning(execution.spec.name)) { this.controller.stop(restart = true) } @@ -58,15 +58,15 @@ class ExecutionHandler( if (gson.toJson(oldExecution.spec) != gson.toJson(newExecution.spec)) { logger.info { "Receive update event for execution ${oldExecution.metadata.name}" } when (this.stateHandler.getExecutionState(newExecution.metadata.name)) { - States.RUNNING -> { - this.stateHandler.setExecutionState(newExecution.spec.name, States.RESTART) + ExecutionStates.RUNNING -> { + this.stateHandler.setExecutionState(newExecution.spec.name, ExecutionStates.RESTART) if (this.controller.isExecutionRunning(newExecution.spec.name)) { this.controller.stop(restart = true) } } - States.RESTART -> { + ExecutionStates.RESTART -> { } // should this set to pending? - else -> this.stateHandler.setExecutionState(newExecution.spec.name, States.PENDING) + else -> this.stateHandler.setExecutionState(newExecution.spec.name, ExecutionStates.PENDING) } } } @@ -79,7 +79,7 @@ class ExecutionHandler( @Synchronized override fun onDelete(execution: ExecutionCRD, b: Boolean) { logger.info { "Delete execution ${execution.metadata.name}" } - if (execution.status.executionState == States.RUNNING.value + if (execution.status.executionState == ExecutionStates.RUNNING.value && this.controller.isExecutionRunning(execution.metadata.name) ) { this.controller.stop() diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt index bcc86c8f2a9b233fa9a1972a866936e14688ecf8..9f49cf3ee4f9f62e7006dbf6697340e1af152f27 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/ExecutionStateHandler.kt @@ -4,7 +4,7 @@ import io.fabric8.kubernetes.client.NamespacedKubernetesClient import theodolite.model.crd.BenchmarkExecutionList import theodolite.model.crd.ExecutionCRD import theodolite.model.crd.ExecutionStatus -import theodolite.model.crd.States +import theodolite.model.crd.ExecutionStates import java.lang.Thread.sleep import java.time.Duration import java.time.Instant @@ -23,17 +23,17 @@ class ExecutionStateHandler(val client: NamespacedKubernetesClient) : private fun getDurationLambda() = { cr: ExecutionCRD -> cr.status.executionDuration } - fun setExecutionState(resourceName: String, status: States): Boolean { + fun setExecutionState(resourceName: String, status: ExecutionStates): Boolean { setState(resourceName) { cr -> cr.status.executionState = status.value; cr } return blockUntilStateIsSet(resourceName, status.value, getExecutionLambda()) } - fun getExecutionState(resourceName: String): States { + fun getExecutionState(resourceName: String): ExecutionStates { val status = this.getState(resourceName, getExecutionLambda()) return if (status.isNullOrBlank()) { - States.NO_STATE + ExecutionStates.NO_STATE } else { - States.values().first { it.value == status } + ExecutionStates.values().first { it.value == status } } } diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt index eb51a445ee05f1811a8780ff64c570f0bbdff4d0..70e30cf84ef40796eb085a0d68eb2e323232fde9 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteController.kt @@ -28,7 +28,8 @@ const val CREATED_BY_LABEL_VALUE = "theodolite" class TheodoliteController( private val executionCRDClient: MixedOperation<ExecutionCRD, BenchmarkExecutionList, Resource<ExecutionCRD>>, private val benchmarkCRDClient: MixedOperation<BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>>, - private val executionStateHandler: ExecutionStateHandler + private val executionStateHandler: ExecutionStateHandler, + private val benchmarkStateHandler: BenchmarkStateHandler ) { lateinit var executor: TheodoliteExecutor @@ -40,6 +41,7 @@ class TheodoliteController( sleep(5000) // wait until all states are correctly set while (true) { reconcile() + updateBenchmarkStatus() sleep(2000) } } @@ -47,8 +49,10 @@ class TheodoliteController( private fun reconcile() { do { val execution = getNextExecution() + updateBenchmarkStatus() if (execution != null) { val benchmark = getBenchmarks() + .map { it.spec } .firstOrNull { it.name == execution.benchmark } if (benchmark != null) { runExecution(execution, benchmark) @@ -65,9 +69,11 @@ class TheodoliteController( * @see BenchmarkExecution */ private fun runExecution(execution: BenchmarkExecution, benchmark: KubernetesBenchmark) { - val modifier = ConfigOverrideModifier( + try { + val modifier = ConfigOverrideModifier( execution = execution, - resources = benchmark.appResource + benchmark.loadGenResource + resources = benchmark.loadKubernetesResources(benchmark.sut.resources).map { it.first } + + benchmark.loadKubernetesResources(benchmark.loadGenerator.resources).map { it.first } ) modifier.setAdditionalLabels( labelValue = execution.name, @@ -82,23 +88,31 @@ class TheodoliteController( labelName = CREATED_BY_LABEL_NAME ) - executionStateHandler.setExecutionState(execution.name, States.RUNNING) + executionStateHandler.setExecutionState(execution.name, ExecutionStates.RUNNING) executionStateHandler.startDurationStateTimer(execution.name) - try { executor = TheodoliteExecutor(execution, benchmark) executor.run() when (executionStateHandler.getExecutionState(execution.name)) { - States.RESTART -> runExecution(execution, benchmark) - States.RUNNING -> { - executionStateHandler.setExecutionState(execution.name, States.FINISHED) + ExecutionStates.RESTART -> runExecution(execution, benchmark) + ExecutionStates.RUNNING -> { + executionStateHandler.setExecutionState(execution.name, ExecutionStates.FINISHED) logger.info { "Execution of ${execution.name} is finally stopped." } + } + else -> { + executionStateHandler.setExecutionState(execution.name, ExecutionStates.FAILURE) + logger.warn { "Unexpected execution state, set state to ${ExecutionStates.FAILURE.value}" } } } } catch (e: Exception) { + EventCreator().createEvent( + executionName = execution.name, + type = "WARNING", + reason = "Execution failed", + message = "An error occurs while executing: ${e.message}") logger.error { "Failure while executing execution ${execution.name} with benchmark ${benchmark.name}." } logger.error { "Problem is: $e" } - executionStateHandler.setExecutionState(execution.name, States.FAILURE) + executionStateHandler.setExecutionState(execution.name, ExecutionStates.FAILURE) } executionStateHandler.stopDurationStateTimer() } @@ -107,7 +121,7 @@ class TheodoliteController( fun stop(restart: Boolean = false) { if (!::executor.isInitialized) return if (restart) { - executionStateHandler.setExecutionState(this.executor.getExecution().name, States.RESTART) + executionStateHandler.setExecutionState(this.executor.getExecution().name, ExecutionStates.RESTART) } this.executor.executor.run.set(false) } @@ -115,30 +129,33 @@ class TheodoliteController( /** * @return all available [BenchmarkCRD]s */ - private fun getBenchmarks(): List<KubernetesBenchmark> { + private fun getBenchmarks(): List<BenchmarkCRD> { return this.benchmarkCRDClient .list() .items .map { it.spec.name = it.metadata.name - it.spec + it } } + /** * Get the [BenchmarkExecution] for the next run. Which [BenchmarkExecution] * is selected for the next execution depends on three points: * * 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, + * 2. The Status of the execution must be [ExecutionStates.PENDING] or [ExecutionStates.RESTART] + * 3. Of the remaining [BenchmarkCRD], those with status [ExecutionStates.RESTART] are preferred, * then, if there is more than one, the oldest execution is chosen. * * @return the next execution or null */ private fun getNextExecution(): BenchmarkExecution? { - val comparator = ExecutionStateComparator(States.RESTART) + val comparator = ExecutionStateComparator(ExecutionStates.RESTART) val availableBenchmarkNames = getBenchmarks() + .filter { it.status.resourceSetsState == BenchmarkStates.READY.value } + .map { it.spec } .map { it.name } return executionCRDClient @@ -147,8 +164,8 @@ class TheodoliteController( .asSequence() .map { it.spec.name = it.metadata.name; it } .filter { - it.status.executionState == States.PENDING.value || - it.status.executionState == States.RESTART.value + it.status.executionState == ExecutionStates.PENDING.value || + it.status.executionState == ExecutionStates.RESTART.value } .filter { availableBenchmarkNames.contains(it.spec.benchmark) } .sortedWith(comparator.thenBy { it.metadata.creationTimestamp }) @@ -156,6 +173,35 @@ class TheodoliteController( .firstOrNull() } + private fun updateBenchmarkStatus() { + this.benchmarkCRDClient + .list() + .items + .map { it.spec.name = it.metadata.name; it } + .map { Pair(it, checkResource(it.spec)) } + .forEach { setState(it.first, it.second ) } + } + + private fun setState(resource: BenchmarkCRD, state: BenchmarkStates) { + benchmarkStateHandler.setResourceSetState(resource.spec.name, state) + } + + private fun checkResource(benchmark: KubernetesBenchmark): BenchmarkStates { + return try { + val appResources = + benchmark.loadKubernetesResources(resourceSet = benchmark.sut.resources) + val loadGenResources = + benchmark.loadKubernetesResources(resourceSet = benchmark.sut.resources) + if(appResources.isNotEmpty() && loadGenResources.isNotEmpty()) { + BenchmarkStates.READY + } else { + BenchmarkStates.PENDING + } + } catch (e: Exception) { + BenchmarkStates.PENDING + } + } + fun isExecutionRunning(executionName: String): Boolean { if (!::executor.isInitialized) return false return this.executor.getExecution().name == executionName diff --git a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt index 2aaba77c03884d94c4d5745db270e84324482878..4850a44fdddba117178e29d3170f44a95df646e7 100644 --- a/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt +++ b/theodolite/src/main/kotlin/theodolite/execution/operator/TheodoliteOperator.kt @@ -11,6 +11,7 @@ import theodolite.model.crd.BenchmarkCRD import theodolite.model.crd.BenchmarkExecutionList import theodolite.model.crd.ExecutionCRD import theodolite.model.crd.KubernetesBenchmarkList +import theodolite.util.Configuration private const val DEFAULT_NAMESPACE = "default" @@ -27,17 +28,18 @@ private val logger = KotlinLogging.logger {} * **See Also:** [Kubernetes Operator Pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) */ class TheodoliteOperator { - private val namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE + private val namespace = Configuration.NAMESPACE private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace) private lateinit var controller: TheodoliteController private lateinit var executionStateHandler: ExecutionStateHandler + private lateinit var benchmarkStateHandler: BenchmarkStateHandler fun start() { LeaderElector( client = client, - name = "theodolite-operator" // TODO(make leaslock name configurable via env var) + name = Configuration.COMPONENT_NAME ) .getLeadership(::startOperator) } @@ -68,7 +70,9 @@ class TheodoliteOperator { controller = getController( client = client, - executionStateHandler = getExecutionStateHandler(client = client) + executionStateHandler = getExecutionStateHandler(client = client), + benchmarkStateHandler = getBenchmarkStateHandler(client = client) + ) getExecutionEventHandler(controller, client).startAllRegisteredInformers() controller.run() @@ -101,21 +105,30 @@ class TheodoliteOperator { return executionStateHandler } + fun getBenchmarkStateHandler(client: NamespacedKubernetesClient) : BenchmarkStateHandler { + if (!::benchmarkStateHandler.isInitialized) { + this.benchmarkStateHandler = BenchmarkStateHandler(client = client) + } + return benchmarkStateHandler + } + fun getController( client: NamespacedKubernetesClient, - executionStateHandler: ExecutionStateHandler + executionStateHandler: ExecutionStateHandler, + benchmarkStateHandler: BenchmarkStateHandler ): TheodoliteController { if (!::controller.isInitialized) { this.controller = TheodoliteController( benchmarkCRDClient = getBenchmarkClient(client), executionCRDClient = getExecutionClient(client), - executionStateHandler = executionStateHandler + executionStateHandler = executionStateHandler, + benchmarkStateHandler = benchmarkStateHandler ) } return this.controller } - private fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation< + fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation< ExecutionCRD, BenchmarkExecutionList, Resource<ExecutionCRD>> { @@ -125,7 +138,7 @@ class TheodoliteOperator { ) } - private fun getBenchmarkClient(client: NamespacedKubernetesClient): MixedOperation< + fun getBenchmarkClient(client: NamespacedKubernetesClient): MixedOperation< BenchmarkCRD, KubernetesBenchmarkList, Resource<BenchmarkCRD>> { diff --git a/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt b/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt index ab355677ec53216072fb58a170610aa5f12dba28..797ed88389947d66aa626ba2ef3fdf6732f8369d 100644 --- a/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt +++ b/theodolite/src/main/kotlin/theodolite/k8s/CustomResourceWrapper.kt @@ -8,7 +8,7 @@ import mu.KotlinLogging private val logger = KotlinLogging.logger {} class CustomResourceWrapper( - private val crAsMap: Map<String, String>, + val crAsMap: Map<String, String>, private val context: CustomResourceDefinitionContext ) : KubernetesResource { /** @@ -33,7 +33,7 @@ class CustomResourceWrapper( client.customResource(this.context) .delete(client.configuration.namespace, this.getName()) } catch (e: Exception) { - logger.warn { "Could not delete service monitor" } + logger.warn { "Could not delete custom resource" } } } diff --git a/theodolite/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt b/theodolite/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt deleted file mode 100644 index faae5ade28deb579df6a463007cbdfbc9cc7706e..0000000000000000000000000000000000000000 --- a/theodolite/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt +++ /dev/null @@ -1,156 +0,0 @@ -package theodolite.k8s - -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.client.NamespacedKubernetesClient -import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext -import mu.KotlinLogging -import theodolite.util.YamlParser - -private val logger = KotlinLogging.logger {} - -/** - * Used to load different Kubernetes resources. - * Supports: Deployments, Services, ConfigMaps, and CustomResources. - * @param client KubernetesClient used to deploy or remove. - */ -class K8sResourceLoader(private val client: NamespacedKubernetesClient) { - - /** - * Parses a Service from a service yaml - * @param path of the yaml file - * @return Service from fabric8 - */ - private fun loadService(path: String): Service { - return loadGenericResource(path) { client.services().load(it).get() } - } - - - /** - * Parses a CustomResource from a yaml - * @param path of the yaml file - * @param context specific crd context for this custom resource - * @return CustomResourceWrapper from fabric8 - */ - private fun loadCustomResourceWrapper( - path: String, - context: CustomResourceDefinitionContext - ): CustomResourceWrapper { - return loadGenericResource(path) { - CustomResourceWrapper( - YamlParser().parse( - path, - HashMap<String, String>()::class.java - )!!, - context - ) - } - } - - private fun loadServiceMonitor(path: String): CustomResourceWrapper { - val context = K8sContextFactory().create( - api = "v1", - scope = "Namespaced", - group = "monitoring.coreos.com", - plural = "servicemonitors" - ) - return loadCustomResourceWrapper(path, context) - } - - private fun loadExecution(path: String): KubernetesResource { - val context = K8sContextFactory().create( - api = "v1", - scope = "Namespaced", - group = "theodolite.com", - plural = "executions" - ) - return loadCustomResourceWrapper(path, context) - } - - private fun loadBenchmark(path: String): KubernetesResource { - val context = K8sContextFactory().create( - api = "v1", - scope = "Namespaced", - group = "theodolite.com", - plural = "benchmarks" - ) - return loadCustomResourceWrapper(path, context) - } - - - /** - * Parses a Deployment from a Deployment yaml - * @param path of the yaml file - * @return Deployment from fabric8 - */ - private fun loadDeployment(path: String): Deployment { - return loadGenericResource(path) { client.apps().deployments().load(it).get() } - } - - /** - * Parses a ConfigMap from a ConfigMap yaml - * @param path of the yaml file - * @return ConfigMap from fabric8 - */ - private fun loadConfigmap(path: String): ConfigMap { - return loadGenericResource(path) { client.configMaps().load(it).get() } - } - - /** - * Parses a StatefulSet from a StatefulSet yaml - * @param path of the yaml file - * @return StatefulSet from fabric8 - */ - private fun loadStatefulSet(path: String): KubernetesResource { - return loadGenericResource(path) { client.apps().statefulSets().load(it).get() } - - } - - /** - * Generic helper function to load a resource. - * @param path of the resource - * @param f function that is applied to the resource. - * @throws IllegalArgumentException If the resource could not be loaded. - */ - private fun <T> loadGenericResource(path: String, f: (String) -> T): T { - var resource: T? = null - - try { - resource = f(path) - } catch (e: Exception) { - logger.warn { "You potentially misspelled the path: $path" } - logger.warn { e } - } - - if (resource == null) { - throw IllegalArgumentException("The Resource at path: $path could not be loaded") - } - return resource - } - - /** - * Factory function used to load different k8s resources from a path. - * Supported kinds are: Deployments, Services, ServiceMonitors, ConfigMaps and CustomResources. - * Uses CustomResource as default if Kind is not supported. - * @param kind of the resource. CustomResource as default. - * @param path of the resource to be loaded. - * @throws Exception if the resource could not be loaded. - */ - fun loadK8sResource(kind: String, path: String): KubernetesResource { - return when (kind) { - "Deployment" -> loadDeployment(path) - "Service" -> loadService(path) - "ServiceMonitor" -> loadServiceMonitor(path) - "ConfigMap" -> loadConfigmap(path) - "StatefulSet" -> loadStatefulSet(path) - "Execution" -> loadExecution(path) - "Benchmark" -> loadBenchmark(path) - else -> { - logger.error { "Error during loading of unspecified resource Kind" } - throw IllegalArgumentException("error while loading resource with kind: $kind") - } - } - } -} diff --git a/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt b/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt index 8e83883fc881db0f7e2b1b75b2fb7c7322a11a00..f2afd71f6e4b4cf8e7106a8fc8a9bd113d9f36e6 100644 --- a/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt +++ b/theodolite/src/main/kotlin/theodolite/k8s/TopicManager.kt @@ -30,8 +30,7 @@ class TopicManager(private val kafkaConfig: Map<String, Any>) { result = kafkaAdmin.createTopics(newTopics) result.all().get() // wait for the future to be completed } catch (e: Exception) { // TopicExistsException - logger.warn(e) { "Error during topic creation." } - logger.debug { e } // TODO remove due to attached exception to warn log? + logger.warn { "Error during topic creation. Error is: ${e.message}" } logger.info { "Remove existing topics." } delete(newTopics.map { topic -> topic.name() }, kafkaAdmin) logger.info { "Will retry the topic creation in ${RETRY_TIME / 1000} seconds." } @@ -94,7 +93,7 @@ class TopicManager(private val kafkaConfig: Map<String, Any>) { }" } } catch (e: Exception) { - logger.error(e) { "Error while removing topics: $e" } + logger.error { "Error while removing topics: ${e.message}" } logger.info { "Existing topics are: ${kafkaAdmin.listTopics().names().get()}." } } diff --git a/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/AbstractK8sLoader.kt b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/AbstractK8sLoader.kt new file mode 100644 index 0000000000000000000000000000000000000000..862de14e2a7a4721e15215b0a1389e14f943fe24 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/AbstractK8sLoader.kt @@ -0,0 +1,73 @@ +package theodolite.k8s.resourceLoader + +import io.fabric8.kubernetes.api.model.KubernetesResource +import mu.KotlinLogging +import theodolite.k8s.K8sContextFactory + +private val logger = KotlinLogging.logger {} + +abstract class AbstractK8sLoader: K8sResourceLoader { + + fun loadK8sResource(kind: String, resourceString: String): KubernetesResource { + return when (kind.replaceFirst(kind[0],kind[0].toUpperCase())) { + "Deployment" -> loadDeployment(resourceString) + "Service" -> loadService(resourceString) + "ServiceMonitor" -> loadServiceMonitor(resourceString) + "ConfigMap" -> loadConfigmap(resourceString) + "StatefulSet" -> loadStatefulSet(resourceString) + "Execution" -> loadExecution(resourceString) + "Benchmark" -> loadBenchmark(resourceString) + else -> { + logger.error { "Error during loading of unspecified resource Kind $kind" } + throw java.lang.IllegalArgumentException("error while loading resource with kind: $kind") + } + } + } + + fun <T> loadGenericResource(resourceString: String, f: (String) -> T): T { + var resource: T? = null + + try { + resource = f(resourceString) + } catch (e: Exception) { + logger.warn { e } + } + + if (resource == null) { + throw IllegalArgumentException("The Resource: $resourceString could not be loaded") + } + return resource + } + + + + override fun loadServiceMonitor(resource: String): KubernetesResource { + val context = K8sContextFactory().create( + api = "v1", + scope = "Namespaced", + group = "monitoring.coreos.com", + plural = "servicemonitors" + ) + return loadCustomResourceWrapper(resource, context) + } + + override fun loadExecution(resource: String): KubernetesResource { + val context = K8sContextFactory().create( + api = "v1", + scope = "Namespaced", + group = "theodolite.com", + plural = "executions" + ) + return loadCustomResourceWrapper(resource, context) + } + + override fun loadBenchmark(resource: String): KubernetesResource { + val context = K8sContextFactory().create( + api = "v1", + scope = "Namespaced", + group = "theodolite.com", + plural = "benchmarks" + ) + return loadCustomResourceWrapper(resource, context) + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoader.kt b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoader.kt new file mode 100644 index 0000000000000000000000000000000000000000..c123ab2958132cb43ad188136f738b561e91310b --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoader.kt @@ -0,0 +1,15 @@ +package theodolite.k8s.resourceLoader + +import io.fabric8.kubernetes.api.model.KubernetesResource +import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext + +interface K8sResourceLoader { + fun loadDeployment(resource: String): KubernetesResource + fun loadService(resource: String): KubernetesResource + fun loadStatefulSet(resource: String): KubernetesResource + fun loadExecution(resource: String): KubernetesResource + fun loadBenchmark(resource: String): KubernetesResource + fun loadConfigmap(resource: String): KubernetesResource + fun loadServiceMonitor(resource: String): KubernetesResource + fun loadCustomResourceWrapper(resource: String, context: CustomResourceDefinitionContext): KubernetesResource +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoaderFromFile.kt b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoaderFromFile.kt new file mode 100644 index 0000000000000000000000000000000000000000..08f34e1d67c9821c9f9a07a49f4ba8683a072611 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoaderFromFile.kt @@ -0,0 +1,75 @@ +package theodolite.k8s.resourceLoader + +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.client.NamespacedKubernetesClient +import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext +import theodolite.k8s.CustomResourceWrapper +import theodolite.util.YamlParserFromFile + +/** + * Used to load different Kubernetes resources. + * Supports: Deployments, Services, ConfigMaps, and CustomResources. + * @param client KubernetesClient used to deploy or remove. + */ +class K8sResourceLoaderFromFile(private val client: NamespacedKubernetesClient): AbstractK8sLoader(), + K8sResourceLoader { + + /** + * Parses a Service from a service yaml + * @param resource of the yaml file + * @return Service from fabric8 + */ + override fun loadService(resource: String): Service { + return loadGenericResource(resource) { x: String -> client.services().load(x).get() } + } + + + /** + * Parses a CustomResource from a yaml + * @param path of the yaml file + * @param context specific crd context for this custom resource + * @return CustomResourceWrapper from fabric8 + */ + override fun loadCustomResourceWrapper(resource: String, context: CustomResourceDefinitionContext): CustomResourceWrapper { + return loadGenericResource(resource) { + CustomResourceWrapper( + YamlParserFromFile().parse( + resource, + HashMap<String, String>()::class.java + )!!, + context + ) + } + } + + /** + * Parses a Deployment from a Deployment yaml + * @param resource of the yaml file + * @return Deployment from fabric8 + */ + override fun loadDeployment(resource: String): Deployment { + return loadGenericResource(resource) { x: String -> client.apps().deployments().load(x).get() } + } + + /** + * Parses a ConfigMap from a ConfigMap yaml + * @param resource of the yaml file + * @return ConfigMap from fabric8 + */ + override fun loadConfigmap(resource: String): ConfigMap { + return loadGenericResource(resource) { x: String -> client.configMaps().load(x).get() } + } + + /** + * Parses a StatefulSet from a StatefulSet yaml + * @param resource of the yaml file + * @return StatefulSet from fabric8 + */ + override fun loadStatefulSet(resource: String): KubernetesResource { + return loadGenericResource(resource) { x: String -> client.apps().statefulSets().load(x).get() } + + } +} diff --git a/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoaderFromString.kt b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoaderFromString.kt new file mode 100644 index 0000000000000000000000000000000000000000..e9611aaa82870dfb676820029cf42c5aab63d672 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/k8s/resourceLoader/K8sResourceLoaderFromString.kt @@ -0,0 +1,60 @@ +package theodolite.k8s.resourceLoader + +import io.fabric8.kubernetes.api.model.ConfigMap +import io.fabric8.kubernetes.api.model.KubernetesResource +import io.fabric8.kubernetes.api.model.apps.Deployment +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext +import theodolite.k8s.CustomResourceWrapper +import theodolite.util.YamlParserFromString +import java.io.ByteArrayInputStream + +class K8sResourceLoaderFromString(private val client: NamespacedKubernetesClient): AbstractK8sLoader(), + K8sResourceLoader { + + @OptIn(ExperimentalStdlibApi::class) + override fun loadService(resource: String): KubernetesResource { + return loadGenericResource(resource) { x: String -> + val stream = ByteArrayInputStream(x.encodeToByteArray()) + client.services().load(stream).get() } + } + + @OptIn(ExperimentalStdlibApi::class) + override fun loadDeployment(resource: String): Deployment { + return loadGenericResource(resource) { x: String -> + val stream = ByteArrayInputStream(x.encodeToByteArray()) + client.apps().deployments().load(stream).get() } + } + + @OptIn(ExperimentalStdlibApi::class) + override fun loadConfigmap(resource: String): ConfigMap { + return loadGenericResource(resource) { x: String -> + val stream = ByteArrayInputStream(x.encodeToByteArray()) + client.configMaps().load(stream).get() } + } + + @OptIn(ExperimentalStdlibApi::class) + override fun loadStatefulSet(resource: String): KubernetesResource { + return loadGenericResource(resource) { x: String -> + val stream = ByteArrayInputStream(x.encodeToByteArray()) + client.apps().statefulSets().load(stream).get() } + } + + /** + * Parses a CustomResource from a yaml + * @param resource of the yaml file + * @param context specific crd context for this custom resource + * @return CustomResourceWrapper from fabric8 + */ + override fun loadCustomResourceWrapper(resource: String, context: CustomResourceDefinitionContext): CustomResourceWrapper { + return loadGenericResource(resource) { + CustomResourceWrapper( + YamlParserFromString().parse( + resource, + HashMap<String, String>()::class.java + )!!, + context + ) + } + } +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkCRD.kt b/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkCRD.kt index 377708af7b7e1a50ae1e33064b2668c364e0685a..b6468fff523e57b124e144d5b9fef6477973655a 100644 --- a/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkCRD.kt +++ b/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkCRD.kt @@ -14,5 +14,6 @@ import theodolite.benchmark.KubernetesBenchmark @Group("theodolite.com") @Kind("benchmark") class BenchmarkCRD( - var spec: KubernetesBenchmark = KubernetesBenchmark() -) : CustomResource<KubernetesBenchmark, Void>(), Namespaced, HasMetadata \ No newline at end of file + var spec: KubernetesBenchmark = KubernetesBenchmark(), + var status: BenchmarkStatus = BenchmarkStatus() +) : CustomResource<KubernetesBenchmark, BenchmarkStatus>(), Namespaced, HasMetadata \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkStates.kt b/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkStates.kt new file mode 100644 index 0000000000000000000000000000000000000000..f52f2c168765ebb8bcc4f390795aa470b968021b --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkStates.kt @@ -0,0 +1,6 @@ +package theodolite.model.crd + +enum class BenchmarkStates(val value: String) { + PENDING("Pending"), + READY("Ready") +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkStatus.kt b/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkStatus.kt new file mode 100644 index 0000000000000000000000000000000000000000..f51cb7a76d015d6ecd900279e68d41baa26e876a --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/model/crd/BenchmarkStatus.kt @@ -0,0 +1,11 @@ +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 + +@JsonDeserialize +class BenchmarkStatus: KubernetesResource, Namespaced { + var resourceSetsState = "-" + +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/model/crd/ExecutionStates.kt b/theodolite/src/main/kotlin/theodolite/model/crd/ExecutionStates.kt new file mode 100644 index 0000000000000000000000000000000000000000..ad68bf380b18af1a654c201817bb7fc982804c8b --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/model/crd/ExecutionStates.kt @@ -0,0 +1,12 @@ +package theodolite.model.crd + +enum class ExecutionStates(val value: String) { + // Execution states + 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/src/main/kotlin/theodolite/model/crd/States.kt b/theodolite/src/main/kotlin/theodolite/model/crd/States.kt deleted file mode 100644 index 79af297915b6703b209acb0c13913482e54db2be..0000000000000000000000000000000000000000 --- a/theodolite/src/main/kotlin/theodolite/model/crd/States.kt +++ /dev/null @@ -1,11 +0,0 @@ -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/src/main/kotlin/theodolite/patcher/PatcherFactory.kt b/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt index cdf115a0755e8794075884bf952db3b8d76f1f50..ebad5de74a6b819dbf7887dfad91faac37ed5074 100644 --- a/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt +++ b/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt @@ -26,7 +26,7 @@ class PatcherFactory { */ fun createPatcher( patcherDefinition: PatcherDefinition, - k8sResources: List<Pair<String, KubernetesResource>> + k8sResources: Collection<Pair<String, KubernetesResource>> ): Patcher { val resource = k8sResources.filter { it.first == patcherDefinition.resource } diff --git a/theodolite/src/main/kotlin/theodolite/util/Configuration.kt b/theodolite/src/main/kotlin/theodolite/util/Configuration.kt new file mode 100644 index 0000000000000000000000000000000000000000..dac3b943e69bd7e208d318f2a788275f19db11e4 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/util/Configuration.kt @@ -0,0 +1,18 @@ +package theodolite.util + +import theodolite.execution.ExecutionModes + +// Defaults +private const val DEFAULT_NAMESPACE = "default" +private const val DEFAULT_COMPONENT_NAME = "theodolite-operator" + + +class Configuration( +) { + companion object { + val NAMESPACE = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE + val COMPONENT_NAME = System.getenv("COMPONENT_NAME") ?: DEFAULT_COMPONENT_NAME + val EXECUTION_MODE = System.getenv("MODE") ?: ExecutionModes.STANDALONE.value + } + +} diff --git a/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt b/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt index 639a7c86c641cbdcba361410cf5e25fa56dd795f..9f4caedf3db1e09dca7924bf0035c6ace0b835d7 100644 --- a/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt +++ b/theodolite/src/main/kotlin/theodolite/util/DeploymentFailedException.kt @@ -1,4 +1,4 @@ package theodolite.util -class DeploymentFailedException(message: String) : Exception(message) \ No newline at end of file +open class DeploymentFailedException(message: String, e: Exception? = null) : TheodoliteException(message,e) diff --git a/theodolite/src/main/kotlin/theodolite/util/EvaluationFailedException.kt b/theodolite/src/main/kotlin/theodolite/util/EvaluationFailedException.kt new file mode 100644 index 0000000000000000000000000000000000000000..c67ed7ffd79afc733a97dae05c3203f8e78722ea --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/util/EvaluationFailedException.kt @@ -0,0 +1,4 @@ +package theodolite.util + +class EvaluationFailedException(message: String, e: Exception? = null) : ExecutionFailedException(message,e) { +} diff --git a/theodolite/src/main/kotlin/theodolite/util/ExecutionFailedException.kt b/theodolite/src/main/kotlin/theodolite/util/ExecutionFailedException.kt new file mode 100644 index 0000000000000000000000000000000000000000..6566a451a3e273214f59962531b6bd17b33a850d --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/util/ExecutionFailedException.kt @@ -0,0 +1,4 @@ +package theodolite.util + +open class ExecutionFailedException(message: String, e: Exception? = null) : TheodoliteException(message,e) { +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/util/ExecutionStateComparator.kt b/theodolite/src/main/kotlin/theodolite/util/ExecutionStateComparator.kt index 66ebe12d6505296682744c10c69f182f07d1a16e..8a6b0e9a49362afa401cf3c1279e7f7f6cddf85d 100644 --- a/theodolite/src/main/kotlin/theodolite/util/ExecutionStateComparator.kt +++ b/theodolite/src/main/kotlin/theodolite/util/ExecutionStateComparator.kt @@ -1,13 +1,13 @@ package theodolite.util import theodolite.model.crd.ExecutionCRD -import theodolite.model.crd.States +import theodolite.model.crd.ExecutionStates -class ExecutionStateComparator(private val preferredState: States): Comparator<ExecutionCRD> { +class ExecutionStateComparator(private val preferredState: ExecutionStates): Comparator<ExecutionCRD> { /** * Simple comparator which can be used to order a list of [ExecutionCRD] such that executions with - * status [States.RESTART] are before all other executions. + * status [ExecutionStates.RESTART] are before all other executions. */ override fun compare(p0: ExecutionCRD, p1: ExecutionCRD): Int { return when { diff --git a/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt b/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt index 81ea227d0d9871c2420a414d81749a34b97676b8..d02948ad341207051c4653ba9400ac0ffe5b03aa 100644 --- a/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt +++ b/theodolite/src/main/kotlin/theodolite/util/InvalidPatcherConfigurationException.kt @@ -1,4 +1,3 @@ package theodolite.util -class InvalidPatcherConfigurationException(message: String, e: Exception? = null) : Exception(message, e) - +class InvalidPatcherConfigurationException(message: String, e: Exception? = null) : DeploymentFailedException(message,e) diff --git a/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt b/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt index bf33fcf6104645727a13b92cf3a13d36e04a10c6..9b0b0dd4e0a5a48072ca576e874cb850c5f8df3b 100644 --- a/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt +++ b/theodolite/src/main/kotlin/theodolite/util/PrometheusResponse.kt @@ -23,7 +23,7 @@ data class PrometheusResponse( * 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 group = data?.result?.get(0)?.metric?.toString()!! val values = data?.result?.get(0)?.values val result = mutableListOf<List<String>>() @@ -64,18 +64,9 @@ data class PromResult( /** * Label of the metric */ - var metric: PromMetric? = null, + var metric: Map<String, String>? = null, /** * Values of the metric (e.g. [ [ <unix_time>, "<sample_value>" ], ... ]) */ var values: List<Any>? = null -) - -/** - * Corresponds to the metric field in the range-vector result format of a Prometheus range-query response. - */ -@RegisterForReflection -data class PromMetric( - var group: String? = null -) - +) \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/util/TheodoliteException.kt b/theodolite/src/main/kotlin/theodolite/util/TheodoliteException.kt new file mode 100644 index 0000000000000000000000000000000000000000..fc7453bae6aaa4c5c526eee72c006562ea887eb5 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/util/TheodoliteException.kt @@ -0,0 +1,3 @@ +package theodolite.util + +open class TheodoliteException (message: String, e: Exception? = null) : Exception(message,e) \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/util/YamlParser.kt b/theodolite/src/main/kotlin/theodolite/util/YamlParserFromFile.kt similarity index 92% rename from theodolite/src/main/kotlin/theodolite/util/YamlParser.kt rename to theodolite/src/main/kotlin/theodolite/util/YamlParserFromFile.kt index ce69894e4145372aef07286ae315d11631a4df3f..ae36349e628621bb7ad287d8cf557fbefa3ff5c5 100644 --- a/theodolite/src/main/kotlin/theodolite/util/YamlParser.kt +++ b/theodolite/src/main/kotlin/theodolite/util/YamlParserFromFile.kt @@ -9,7 +9,7 @@ import java.io.InputStream /** * The YamlParser parses a YAML file */ -class YamlParser : Parser { +class YamlParserFromFile : Parser { override fun <T> parse(path: String, E: Class<T>): T? { val input: InputStream = FileInputStream(File(path)) val parser = Yaml(Constructor(E)) diff --git a/theodolite/src/main/kotlin/theodolite/util/YamlParserFromString.kt b/theodolite/src/main/kotlin/theodolite/util/YamlParserFromString.kt new file mode 100644 index 0000000000000000000000000000000000000000..61db189ee99fa5fe36113b0fdecf589ad1114852 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/util/YamlParserFromString.kt @@ -0,0 +1,17 @@ +package theodolite.util + +import org.yaml.snakeyaml.Yaml +import org.yaml.snakeyaml.constructor.Constructor +import java.io.File +import java.io.FileInputStream +import java.io.InputStream + +/** + * The YamlParser parses a YAML string + */ +class YamlParserFromString : Parser { + override fun <T> parse(fileString: String, E: Class<T>): T? { + val parser = Yaml(Constructor(E)) + return parser.loadAs(fileString, E) + } +} diff --git a/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt b/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt index 49131352cfe517a382ddd7aa1be09d3fbe317466..580d9e747bde687a91ffb1bce2e7c9dfb6f166a2 100644 --- a/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt +++ b/theodolite/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, 5) + val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(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, 0) + TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(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, 0) + val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 0) val binarySearch = BinarySearch(benchmarkExecutor) val lowerBoundRestriction = LowerBoundRestriction(results) val strategy = diff --git a/theodolite/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt index e88192dd7fe4393494a4fb76bd74d1123bd75f1d..46758583172c3fcd6417e17ff5bab85f8659734b 100644 --- a/theodolite/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt +++ b/theodolite/src/test/kotlin/theodolite/ResourceLimitPatcherTest.kt @@ -5,7 +5,7 @@ import io.fabric8.kubernetes.client.DefaultKubernetesClient import io.quarkus.test.junit.QuarkusTest import io.smallrye.common.constraint.Assert.assertTrue import org.junit.jupiter.api.Test -import theodolite.k8s.K8sResourceLoader +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile import theodolite.patcher.PatcherFactory import theodolite.util.PatcherDefinition @@ -22,7 +22,7 @@ import theodolite.util.PatcherDefinition @QuarkusTest class ResourceLimitPatcherTest { val testPath = "./src/test/resources/" - val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace("")) + val loader = K8sResourceLoaderFromFile(DefaultKubernetesClient().inNamespace("")) val patcherFactory = PatcherFactory() fun applyTest(fileName: String) { diff --git a/theodolite/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt index 2af6c632567bf47e150a74808ab009bd0bc0598a..8794d4dc2d67b8af78f4fa409c727f882922d0b8 100644 --- a/theodolite/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt +++ b/theodolite/src/test/kotlin/theodolite/ResourceRequestPatcherTest.kt @@ -5,7 +5,7 @@ import io.fabric8.kubernetes.client.DefaultKubernetesClient import io.quarkus.test.junit.QuarkusTest import io.smallrye.common.constraint.Assert.assertTrue import org.junit.jupiter.api.Test -import theodolite.k8s.K8sResourceLoader +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile import theodolite.patcher.PatcherFactory import theodolite.util.PatcherDefinition @@ -22,7 +22,7 @@ import theodolite.util.PatcherDefinition @QuarkusTest class ResourceRequestPatcherTest { val testPath = "./src/test/resources/" - val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace("")) + val loader = K8sResourceLoaderFromFile(DefaultKubernetesClient().inNamespace("")) val patcherFactory = PatcherFactory() fun applyTest(fileName: String) { diff --git a/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt b/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt index 913a27a1b1c1412aa0a58baf9e11fafb1c7f4bd2..b08c1a18a3013e1573e4892f01698b5e509f9609 100644 --- a/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt +++ b/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt @@ -8,6 +8,12 @@ import theodolite.util.Resource class TestBenchmark : Benchmark { + override fun setupInfrastructure() { + } + + override fun teardownInfrastructure() { + } + override fun buildDeployment( load: LoadDimension, res: Resource, diff --git a/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt b/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt index cbd2d5926d61b0bfd4de6fab0c14422ddf88f190..2efddc48cb93a0870d1716c58a7018145c16e2ff 100644 --- a/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt +++ b/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt @@ -12,7 +12,7 @@ class TestBenchmarkExecutorImpl( private val mockResults: Array<Array<Boolean>>, benchmark: Benchmark, results: Results, - slo: BenchmarkExecution.Slo, + slo: List<BenchmarkExecution.Slo>, executionId: Int, loadGenerationDelay: Long, afterTeardownDelay: Long @@ -22,11 +22,12 @@ class TestBenchmarkExecutorImpl( results, executionDuration = Duration.ofSeconds(1), configurationOverrides = emptyList(), - slo = slo, + slos = slo, repetitions = 1, executionId = executionId, loadGenerationDelay = loadGenerationDelay, - afterTeardownDelay = afterTeardownDelay + afterTeardownDelay = afterTeardownDelay, + executionName = "test-execution" ) { override fun runExperiment(load: LoadDimension, res: Resource): Boolean { diff --git a/theodolite/src/test/kotlin/theodolite/benchmark/ConfigMapResourceSetTest.kt b/theodolite/src/test/kotlin/theodolite/benchmark/ConfigMapResourceSetTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..2cc8f931418e28ae8841b592f93df8d88440cf3c --- /dev/null +++ b/theodolite/src/test/kotlin/theodolite/benchmark/ConfigMapResourceSetTest.kt @@ -0,0 +1,226 @@ +package theodolite.benchmark + +import com.google.gson.Gson +import io.fabric8.kubernetes.api.model.* +import io.fabric8.kubernetes.api.model.apps.Deployment +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder +import io.fabric8.kubernetes.api.model.apps.StatefulSet +import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder +import io.fabric8.kubernetes.client.server.mock.KubernetesServer +import io.quarkus.test.junit.QuarkusTest +import io.smallrye.common.constraint.Assert.assertTrue +import junit.framework.Assert.assertEquals +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import theodolite.k8s.CustomResourceWrapper +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile +import theodolite.util.DeploymentFailedException + +private val testResourcePath = "./src/test/resources/k8s-resource-files/" + +@QuarkusTest +class ConfigMapResourceSetTest { + private val server = KubernetesServer(false, true) + + @BeforeEach + fun setUp() { + server.before() + } + + @AfterEach + fun tearDown() { + server.after() + } + + fun deployAndGetResource(resource: String): Collection<Pair<String, KubernetesResource>> { + val configMap1 = ConfigMapBuilder() + .withNewMetadata().withName("test-configmap").endMetadata() + .addToData("test-resource.yaml",resource) + .build() + + server.client.configMaps().createOrReplace(configMap1) + + val resourceSet = ConfigMapResourceSet() + resourceSet.name = "test-configmap" + + return resourceSet.getResourceSet(server.client) + } + + + @Test + fun testLoadDeployment() { + val resourceBuilder = DeploymentBuilder() + resourceBuilder.withNewSpec().endSpec() + resourceBuilder.withNewMetadata().endMetadata() + val resource = resourceBuilder.build() + resource.metadata.name = "test-deployment" + + val createdResource = deployAndGetResource(resource = Gson().toJson(resource)) + assertEquals(1, createdResource.size) + assertTrue(createdResource.toMutableSet().first().second is Deployment) + assertTrue(createdResource.toMutableSet().first().second.toString().contains(other = resource.metadata.name)) + } + + @Test + fun testLoadStateFulSet() { + val resourceBuilder = StatefulSetBuilder() + resourceBuilder.withNewSpec().endSpec() + resourceBuilder.withNewMetadata().endMetadata() + val resource = resourceBuilder.build() + resource.metadata.name = "test-resource" + + val createdResource = deployAndGetResource(resource = Gson().toJson(resource)) + assertEquals(1, createdResource.size) + assertTrue(createdResource.toMutableSet().first().second is StatefulSet) + assertTrue(createdResource.toMutableSet().first().second.toString().contains(other = resource.metadata.name)) + } + + @Test + fun testLoadService() { + val resourceBuilder = ServiceBuilder() + resourceBuilder.withNewSpec().endSpec() + resourceBuilder.withNewMetadata().endMetadata() + val resource = resourceBuilder.build() + resource.metadata.name = "test-resource" + + val createdResource = deployAndGetResource(resource = Gson().toJson(resource)) + assertEquals(1, createdResource.size) + assertTrue(createdResource.toMutableSet().first().second is Service) + assertTrue(createdResource.toMutableSet().first().second.toString().contains(other = resource.metadata.name)) + } + + @Test + fun testLoadConfigMap() { + val resourceBuilder = ConfigMapBuilder() + resourceBuilder.withNewMetadata().endMetadata() + val resource = resourceBuilder.build() + resource.metadata.name = "test-resource" + + val createdResource = deployAndGetResource(resource = Gson().toJson(resource)) + assertEquals(1, createdResource.size) + assertTrue(createdResource.toMutableSet().first().second is ConfigMap) + assertTrue(createdResource.toMutableSet().first().second.toString().contains(other = resource.metadata.name)) + } + + @Test + fun testLoadExecution() { + val loader = K8sResourceLoaderFromFile(server.client) + val resource = loader.loadK8sResource("Execution", testResourcePath + "test-execution.yaml") as CustomResourceWrapper + val createdResource = deployAndGetResource(resource = Gson().toJson(resource.crAsMap)) + + assertEquals(1, createdResource.size) + assertTrue(createdResource.toMutableSet().first().second is CustomResourceWrapper) + + val loadedResource = createdResource.toMutableSet().first().second + if (loadedResource is CustomResourceWrapper){ + assertTrue(loadedResource.getName() == "example-execution") + } + } + + @Test + fun testLoadBenchmark() { + val loader = K8sResourceLoaderFromFile(server.client) + val resource = loader.loadK8sResource("Benchmark", testResourcePath + "test-benchmark.yaml") as CustomResourceWrapper + val createdResource = deployAndGetResource(resource = Gson().toJson(resource.crAsMap)) + + assertEquals(1, createdResource.size) + assertTrue(createdResource.toMutableSet().first().second is CustomResourceWrapper) + + val loadedResource = createdResource.toMutableSet().first().second + if (loadedResource is CustomResourceWrapper){ + assertTrue(loadedResource.getName() == "example-benchmark") + } + } + + @Test + fun testLoadServiceMonitor() { + val loader = K8sResourceLoaderFromFile(server.client) + val resource = loader.loadK8sResource("ServiceMonitor", testResourcePath + "test-service-monitor.yaml") as CustomResourceWrapper + val createdResource = deployAndGetResource(resource = Gson().toJson(resource.crAsMap)) + + assertEquals(1, createdResource.size) + assertTrue(createdResource.toMutableSet().first().second is CustomResourceWrapper) + + val loadedResource = createdResource.toMutableSet().first().second + if (loadedResource is CustomResourceWrapper){ + assertTrue(loadedResource.getName() == "test-service-monitor") + } + } + + @Test + fun testMultipleFiles(){ + val resourceBuilder = DeploymentBuilder() + resourceBuilder.withNewSpec().endSpec() + resourceBuilder.withNewMetadata().endMetadata() + val resource = resourceBuilder.build() + resource.metadata.name = "test-deployment" + + val resourceBuilder1 = ConfigMapBuilder() + resourceBuilder1.withNewMetadata().endMetadata() + val resource1 = resourceBuilder1.build() + resource1.metadata.name = "test-configmap" + + val configMap1 = ConfigMapBuilder() + .withNewMetadata().withName("test-configmap").endMetadata() + .addToData("test-deployment.yaml",Gson().toJson(resource)) + .addToData("test-configmap.yaml",Gson().toJson(resource1)) + .build() + + server.client.configMaps().createOrReplace(configMap1) + + val resourceSet = ConfigMapResourceSet() + resourceSet.name = "test-configmap" + + val createdResourcesSet = resourceSet.getResourceSet(server.client) + + assertEquals(2,createdResourcesSet.size ) + assert(createdResourcesSet.toMutableList()[0].second is Deployment) + assert(createdResourcesSet.toMutableList()[1].second is ConfigMap) + } + + @Test + fun testFileIsSet(){ + val resourceBuilder = DeploymentBuilder() + resourceBuilder.withNewSpec().endSpec() + resourceBuilder.withNewMetadata().endMetadata() + val resource = resourceBuilder.build() + resource.metadata.name = "test-deployment" + + val resourceBuilder1 = ConfigMapBuilder() + resourceBuilder1.withNewMetadata().endMetadata() + val resource1 = resourceBuilder1.build() + resource1.metadata.name = "test-configmap" + + val configMap1 = ConfigMapBuilder() + .withNewMetadata().withName("test-configmap").endMetadata() + .addToData("test-deployment.yaml",Gson().toJson(resource)) + .addToData("test-configmap.yaml",Gson().toJson(resource1)) + .build() + + server.client.configMaps().createOrReplace(configMap1) + + val resourceSet = ConfigMapResourceSet() + resourceSet.name = "test-configmap" + resourceSet.files = listOf("test-deployment.yaml") + + val createdResourcesSet = resourceSet.getResourceSet(server.client) + + assertEquals(1,createdResourcesSet.size ) + assert(createdResourcesSet.toMutableSet().first().second is Deployment) + } + + + @Test() + fun testConfigMapNotExist() { + val resourceSet = ConfigMapResourceSet() + resourceSet.name = "test-configmap1" + lateinit var ex: Exception + try { + resourceSet.getResourceSet(server.client) + } catch (e: Exception) { + ex = e + } + assertTrue(ex is DeploymentFailedException) + } +} \ No newline at end of file diff --git a/theodolite/src/test/kotlin/theodolite/benchmark/FileSystemResourceSetTest.kt b/theodolite/src/test/kotlin/theodolite/benchmark/FileSystemResourceSetTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..59ad2be3248f67442ce352788f8b94b26f3b6b90 --- /dev/null +++ b/theodolite/src/test/kotlin/theodolite/benchmark/FileSystemResourceSetTest.kt @@ -0,0 +1,115 @@ +package theodolite.benchmark + +import io.fabric8.kubernetes.api.model.ConfigMap +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.server.mock.KubernetesServer +import io.smallrye.common.constraint.Assert.assertTrue +import junit.framework.Assert.assertEquals +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import theodolite.k8s.CustomResourceWrapper +import theodolite.util.DeploymentFailedException +import java.lang.IllegalStateException + +private val testResourcePath = "./src/test/resources/k8s-resource-files/" + +class FileSystemResourceSetTest { + + private val server = KubernetesServer(false, true) + + @BeforeEach + fun setUp() { + server.before() + } + + @AfterEach + fun tearDown() { + server.after() + } + + @Test + fun testLoadDeployment() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + resourceSet.files = listOf("test-deployment.yaml") + assertEquals(1,resourceSet.getResourceSet(server.client).size) + assertTrue(resourceSet.getResourceSet(server.client).toMutableSet().first().second is Deployment) + } + + @Test + fun testLoadService() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + resourceSet.files = listOf("test-service.yaml") + assertEquals(1,resourceSet.getResourceSet(server.client).size) + assertTrue(resourceSet.getResourceSet(server.client).toMutableSet().first().second is Service) + } + + @Test + fun testLoadStatefulSet() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + resourceSet.files = listOf("test-statefulset.yaml") + assertEquals(1,resourceSet.getResourceSet(server.client).size) + assertTrue(resourceSet.getResourceSet(server.client).toMutableSet().first().second is StatefulSet) + } + + @Test + fun testLoadConfigMap() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + resourceSet.files = listOf("test-configmap.yaml") + assertEquals(1,resourceSet.getResourceSet(server.client).size) + assertTrue(resourceSet.getResourceSet(server.client).toMutableSet().first().second is ConfigMap) + } + + @Test + fun testLoadServiceMonitor() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + resourceSet.files = listOf("test-service-monitor.yaml") + assertEquals(1,resourceSet.getResourceSet(server.client).size) + assertTrue(resourceSet.getResourceSet(server.client).toMutableSet().first().second is CustomResourceWrapper) + } + + @Test + fun testLoadBenchmark() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + resourceSet.files = listOf("test-benchmark.yaml") + assertEquals(1,resourceSet.getResourceSet(server.client).size) + assertTrue(resourceSet.getResourceSet(server.client).toMutableSet().first().second is CustomResourceWrapper) + } + + @Test + fun testLoadExecution() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + resourceSet.files = listOf("test-execution.yaml") + assertEquals(1,resourceSet.getResourceSet(server.client).size) + assertTrue(resourceSet.getResourceSet(server.client).toMutableSet().first().second is CustomResourceWrapper) + } + + @Test + fun testFilesNotSet() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = testResourcePath + assertEquals(9,resourceSet.getResourceSet(server.client).size) + } + + @Test + fun testWrongPath() { + val resourceSet = FileSystemResourceSet() + resourceSet.path = "/abc/not-exist" + lateinit var ex: Exception + try { + resourceSet.getResourceSet(server.client) + } catch (e: Exception) { + println(e) + ex = e + } + assertTrue(ex is DeploymentFailedException) } +} \ No newline at end of file diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt index f3fd06a16e38439a2a694b415edc4d8b332ffd4d..e294ea539ea60104cc00e9f73de790302ad52670 100644 --- a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt +++ b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt @@ -1,6 +1,7 @@ package theodolite.execution.operator import theodolite.benchmark.KubernetesBenchmark +import theodolite.benchmark.Resources import theodolite.model.crd.BenchmarkCRD import theodolite.util.KafkaConfig @@ -24,8 +25,15 @@ class BenchmarkCRDummy(name: String) { benchmarkCR.kind = "Benchmark" benchmarkCR.apiVersion = "v1" - benchmark.appResource = emptyList() - benchmark.loadGenResource = emptyList() + + benchmark.infrastructure = Resources() + benchmark.sut = Resources() + benchmark.loadGenerator = Resources() + + benchmark.infrastructure.resources = emptyList() + benchmark.sut.resources = emptyList() + benchmark.loadGenerator.resources = emptyList() + benchmark.resourceTypes = emptyList() benchmark.loadTypes = emptyList() benchmark.kafkaConfig = kafkaConfig diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt index 7350f564a71e2f0cbf640b782f5dbf19cbdc7ecb..7e0532aff36cac2fb1a1c718415315b8f54052c2 100644 --- a/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt +++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ControllerTest.kt @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test import theodolite.benchmark.BenchmarkExecution import theodolite.benchmark.KubernetesBenchmark import theodolite.model.crd.BenchmarkCRD +import theodolite.model.crd.BenchmarkStates import theodolite.model.crd.ExecutionCRD @QuarkusTest @@ -33,11 +34,13 @@ class ControllerTest { server.before() this.controller = TheodoliteOperator().getController( client = server.client, - executionStateHandler = ExecutionStateHandler(server.client) + executionStateHandler = ExecutionStateHandler(server.client), + benchmarkStateHandler = BenchmarkStateHandler(server.client) ) // benchmark val benchmark1 = BenchmarkCRDummy(name = "Test-Benchmark") + benchmark1.getCR().status.resourceSetsState = BenchmarkStates.READY.value val benchmark2 = BenchmarkCRDummy(name = "Test-Benchmark-123") benchmarkResourceList.items = listOf(benchmark1.getCR(), benchmark2.getCR()) @@ -111,12 +114,12 @@ class ControllerTest { .getDeclaredMethod("getBenchmarks") method.isAccessible = true - val result = method.invoke(controller) as List<KubernetesBenchmark> + val result = method.invoke(controller) as List<BenchmarkCRD> assertEquals(2, result.size) assertEquals( gson.toJson(benchmark), - gson.toJson(result.firstOrNull()) + gson.toJson(result.firstOrNull()?.spec) ) } diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt index 56d46279e8effe1f0b5bf307cd896ebd5b7eb2ee..51347d41b396bf375c14d5580b0f2619ce5b518c 100644 --- a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt +++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt @@ -3,7 +3,7 @@ package theodolite.execution.operator import theodolite.benchmark.BenchmarkExecution import theodolite.model.crd.ExecutionCRD import theodolite.model.crd.ExecutionStatus -import theodolite.model.crd.States +import theodolite.model.crd.ExecutionStates class ExecutionCRDummy(name: String, benchmark: String) { @@ -51,6 +51,6 @@ class ExecutionCRDummy(name: String, benchmark: String) { execution.configOverrides = mutableListOf() execution.name = executionCR.metadata.name - executionState.executionState = States.PENDING.value + executionState.executionState = ExecutionStates.PENDING.value } } \ No newline at end of file diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt index 5598f48a2d291db4eab8563dd3325534f49b2eb6..d8db7ab3b64ce3856984ddbc279ef148aa325e73 100644 --- a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt +++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt @@ -10,8 +10,8 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import theodolite.k8s.K8sManager -import theodolite.k8s.K8sResourceLoader -import theodolite.model.crd.States +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile +import theodolite.model.crd.ExecutionStates import java.lang.Thread.sleep @@ -36,16 +36,17 @@ class ExecutionEventHandlerTest { val operator = TheodoliteOperator() this.controller = operator.getController( client = server.client, - executionStateHandler = ExecutionStateHandler(client = server.client) + executionStateHandler = ExecutionStateHandler(client = server.client), + benchmarkStateHandler = BenchmarkStateHandler(client = server.client) ) this.factory = operator.getExecutionEventHandler(this.controller, server.client) this.stateHandler = TheodoliteOperator().getExecutionStateHandler(client = server.client) - this.executionVersion1 = K8sResourceLoader(server.client) + this.executionVersion1 = K8sResourceLoaderFromFile(server.client) .loadK8sResource("Execution", testResourcePath + "test-execution.yaml") - this.executionVersion2 = K8sResourceLoader(server.client) + this.executionVersion2 = K8sResourceLoaderFromFile(server.client) .loadK8sResource("Execution", testResourcePath + "test-execution-update.yaml") this.stateHandler = operator.getExecutionStateHandler(server.client) @@ -81,7 +82,7 @@ class ExecutionEventHandlerTest { factory.startAllRegisteredInformers() sleep(500) assertEquals( - States.PENDING, + ExecutionStates.PENDING, stateHandler.getExecutionState( resourceName = executionName ) @@ -95,12 +96,12 @@ class ExecutionEventHandlerTest { stateHandler .setExecutionState( resourceName = executionName, - status = States.RUNNING + status = ExecutionStates.RUNNING ) factory.startAllRegisteredInformers() sleep(500) assertEquals( - States.RESTART, + ExecutionStates.RESTART, stateHandler.getExecutionState( resourceName = executionName ) @@ -116,7 +117,7 @@ class ExecutionEventHandlerTest { sleep(500) assertEquals( - States.PENDING, + ExecutionStates.PENDING, stateHandler.getExecutionState( resourceName = executionName ) @@ -124,7 +125,7 @@ class ExecutionEventHandlerTest { manager.deploy(executionVersion2) assertEquals( - States.PENDING, + ExecutionStates.PENDING, stateHandler.getExecutionState( resourceName = executionName ) @@ -140,14 +141,14 @@ class ExecutionEventHandlerTest { stateHandler.setExecutionState( resourceName = executionName, - status = States.FINISHED + status = ExecutionStates.FINISHED ) manager.deploy(executionVersion2) sleep(500) assertEquals( - States.PENDING, + ExecutionStates.PENDING, stateHandler.getExecutionState( resourceName = executionName ) @@ -163,14 +164,14 @@ class ExecutionEventHandlerTest { stateHandler.setExecutionState( resourceName = executionName, - status = States.FAILURE + status = ExecutionStates.FAILURE ) manager.deploy(executionVersion2) sleep(500) assertEquals( - States.PENDING, + ExecutionStates.PENDING, stateHandler.getExecutionState( resourceName = executionName ) @@ -187,14 +188,14 @@ class ExecutionEventHandlerTest { stateHandler.setExecutionState( resourceName = executionName, - status = States.RUNNING + status = ExecutionStates.RUNNING ) manager.deploy(executionVersion2) sleep(500) assertEquals( - States.RESTART, + ExecutionStates.RESTART, stateHandler.getExecutionState( resourceName = executionName ) @@ -210,14 +211,14 @@ class ExecutionEventHandlerTest { stateHandler.setExecutionState( resourceName = executionName, - status = States.RESTART + status = ExecutionStates.RESTART ) manager.deploy(executionVersion2) sleep(500) assertEquals( - States.RESTART, + ExecutionStates.RESTART, stateHandler.getExecutionState( resourceName = executionName ) diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt index 24cb6c90d8ea222c90a398e12c7a50a2f6058a93..a54f4ed6db559f8f7f15ae82deecf3fedf8b4abe 100644 --- a/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt +++ b/theodolite/src/test/kotlin/theodolite/execution/operator/StateHandlerTest.kt @@ -8,8 +8,8 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import theodolite.k8s.K8sManager -import theodolite.k8s.K8sResourceLoader -import theodolite.model.crd.States +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile +import theodolite.model.crd.ExecutionStates import java.time.Duration class StateHandlerTest { @@ -19,7 +19,7 @@ class StateHandlerTest { @BeforeEach fun setUp() { server.before() - val executionResource = K8sResourceLoader(server.client) + val executionResource = K8sResourceLoaderFromFile(server.client) .loadK8sResource("Execution", testResourcePath + "test-execution.yaml") K8sManager(server.client).deploy(executionResource) @@ -47,7 +47,7 @@ class StateHandlerTest { @DisplayName("Test empty execution state") fun executionWithoutExecutionStatusTest() { val handler = ExecutionStateHandler(client = server.client) - assertEquals(States.NO_STATE, handler.getExecutionState("example-execution")) + assertEquals(ExecutionStates.NO_STATE, handler.getExecutionState("example-execution")) } @Test @@ -62,8 +62,8 @@ class StateHandlerTest { fun executionStatusTest() { val handler = ExecutionStateHandler(client = server.client) - assertTrue(handler.setExecutionState("example-execution", States.INTERRUPTED)) - assertEquals(States.INTERRUPTED, handler.getExecutionState("example-execution")) + assertTrue(handler.setExecutionState("example-execution", ExecutionStates.INTERRUPTED)) + assertEquals(ExecutionStates.INTERRUPTED, handler.getExecutionState("example-execution")) } @Test diff --git a/theodolite/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt b/theodolite/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt index dc2bf016994d79b1021bebdc751102e291d60682..7c69618de03f730f5b6f1cb83c5df544e2cd120c 100644 --- a/theodolite/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt +++ b/theodolite/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt @@ -15,6 +15,7 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile private val logger = KotlinLogging.logger {} @@ -125,7 +126,7 @@ class K8sManagerTest { @DisplayName("Test handling of custom resources") fun handleCustomResourcesTest() { val manager = K8sManager(server.client) - val servicemonitor = K8sResourceLoader(server.client) + val servicemonitor = K8sResourceLoaderFromFile(server.client) .loadK8sResource("ServiceMonitor", testResourcePath + "test-service-monitor.yaml") val serviceMonitorContext = K8sContextFactory().create( diff --git a/theodolite/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt b/theodolite/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt index 7c2aa50007274ff9b4d49f1c0cc05ae45a37d323..4a41dac8b27b9d4ddcfb9915f759b14ea4eaba4a 100644 --- a/theodolite/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt +++ b/theodolite/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test +import theodolite.k8s.resourceLoader.K8sResourceLoaderFromFile @QuarkusTest class K8sResourceLoaderTest { @@ -31,7 +32,7 @@ class K8sResourceLoaderTest { @Test @DisplayName("Test loading of Deployments") fun loadDeploymentTest() { - val loader = K8sResourceLoader(server.client) + val loader = K8sResourceLoaderFromFile(server.client) val resource = loader.loadK8sResource("Deployment", testResourcePath + "test-deployment.yaml") assertTrue(resource is Deployment) @@ -41,7 +42,7 @@ class K8sResourceLoaderTest { @Test @DisplayName("Test loading of StatefulSet") fun loadStatefulSetTest() { - val loader = K8sResourceLoader(server.client) + val loader = K8sResourceLoaderFromFile(server.client) val resource = loader.loadK8sResource("StatefulSet", testResourcePath + "test-statefulset.yaml") assertTrue(resource is StatefulSet) @@ -51,7 +52,7 @@ class K8sResourceLoaderTest { @Test @DisplayName("Test loading of Service") fun loadServiceTest() { - val loader = K8sResourceLoader(server.client) + val loader = K8sResourceLoaderFromFile(server.client) val resource = loader.loadK8sResource("Service", testResourcePath + "test-service.yaml") assertTrue(resource is Service) @@ -61,7 +62,7 @@ class K8sResourceLoaderTest { @Test @DisplayName("Test loading of ConfigMap") fun loadConfigMapTest() { - val loader = K8sResourceLoader(server.client) + val loader = K8sResourceLoaderFromFile(server.client) val resource = loader.loadK8sResource("ConfigMap", testResourcePath + "test-configmap.yaml") assertTrue(resource is ConfigMap) @@ -71,7 +72,7 @@ class K8sResourceLoaderTest { @Test @DisplayName("Test loading of ServiceMonitors") fun loadServiceMonitorTest() { - val loader = K8sResourceLoader(server.client) + val loader = K8sResourceLoaderFromFile(server.client) val resource = loader.loadK8sResource("ServiceMonitor", testResourcePath + "test-service-monitor.yaml") assertTrue(resource is CustomResourceWrapper) @@ -84,7 +85,7 @@ class K8sResourceLoaderTest { @Test @DisplayName("Test loading of Executions") fun loadExecutionTest() { - val loader = K8sResourceLoader(server.client) + val loader = K8sResourceLoaderFromFile(server.client) val resource = loader.loadK8sResource("Execution", testResourcePath + "test-execution.yaml") assertTrue(resource is CustomResourceWrapper) @@ -97,7 +98,7 @@ class K8sResourceLoaderTest { @Test @DisplayName("Test loading of Benchmarks") fun loadBenchmarkTest() { - val loader = K8sResourceLoader(server.client) + val loader = K8sResourceLoaderFromFile(server.client) val resource = loader.loadK8sResource("Benchmark", testResourcePath + "test-benchmark.yaml") assertTrue(resource is CustomResourceWrapper) diff --git a/theodolite/src/test/kotlin/theodolite/patcher/ConfigOverrideModifierTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/ConfigOverrideModifierTest.kt index 739fadd3f02bfd1e60fd67e7afc695bf99e68d31..1db1122e1caa5a783159ecaba849b99963e3c2a9 100644 --- a/theodolite/src/test/kotlin/theodolite/patcher/ConfigOverrideModifierTest.kt +++ b/theodolite/src/test/kotlin/theodolite/patcher/ConfigOverrideModifierTest.kt @@ -27,11 +27,10 @@ class ConfigOverrideModifierTest { @Test fun setAdditionalLabelsTest() { - this.benchmark.appResource = listOf("test-resource.yaml") val modifier = ConfigOverrideModifier( execution = this.execution, - resources = this.benchmark.appResource + resources = listOf("test-resource.yaml") ) modifier.setAdditionalLabels( diff --git a/theodolite/src/test/kotlin/theodolite/util/ExecutionStateComparatorTest.kt b/theodolite/src/test/kotlin/theodolite/util/ExecutionStateComparatorTest.kt index eec029f3878171eb2fd502bf68f549cfce793f23..7332e53f9e1814f28b8ff37a595b31b0eb931ea7 100644 --- a/theodolite/src/test/kotlin/theodolite/util/ExecutionStateComparatorTest.kt +++ b/theodolite/src/test/kotlin/theodolite/util/ExecutionStateComparatorTest.kt @@ -1,14 +1,10 @@ package theodolite.util import io.quarkus.test.junit.QuarkusTest -import org.junit.Rule -import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import theodolite.execution.operator.ExecutionCRDummy -import theodolite.model.crd.ExecutionCRD -import theodolite.model.crd.States +import theodolite.model.crd.ExecutionStates @QuarkusTest @@ -16,11 +12,11 @@ class ExecutionStateComparatorTest { @Test fun testCompare() { - val comparator = ExecutionStateComparator(States.RESTART) + val comparator = ExecutionStateComparator(ExecutionStates.RESTART) val execution1 = ExecutionCRDummy("dummy1", "default-benchmark") val execution2 = ExecutionCRDummy("dummy2", "default-benchmark") - execution1.getStatus().executionState = States.RESTART.value - execution2.getStatus().executionState = States.PENDING.value + execution1.getStatus().executionState = ExecutionStates.RESTART.value + execution2.getStatus().executionState = ExecutionStates.PENDING.value val list = listOf(execution2.getCR(), execution1.getCR()) diff --git a/theodolite/src/test/resources/k8s-resource-files/test-execution-1.yaml b/theodolite/src/test/resources/k8s-resource-files/test-execution-1.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1407a9952b7454053d204454841d51cfb4d7dbf4 --- /dev/null +++ b/theodolite/src/test/resources/k8s-resource-files/test-execution-1.yaml @@ -0,0 +1,28 @@ +apiVersion: theodolite.com/v1 +kind: Execution +metadata: + name: example-execution +spec: + name: test + 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: []