Skip to content
Snippets Groups Projects
Commit 52b1f1fc authored by Benedikt Wetzel's avatar Benedikt Wetzel
Browse files

Merge upstream theodolite-kotlin

parents 1810eb2c b41496e2
No related branches found
No related tags found
4 merge requests!159Re-implementation of Theodolite with Kotlin/Quarkus,!157Update Graal Image in CI pipeline,!111Add prefix to output files to link results and experiment,!83WIP: Re-implementation of Theodolite with Kotlin/Quarkus
Showing
with 121 additions and 55 deletions
...@@ -98,7 +98,7 @@ kubectl apply -f infrastructure/kafka/service-monitor.yaml ...@@ -98,7 +98,7 @@ kubectl apply -f infrastructure/kafka/service-monitor.yaml
Other Kafka deployments, for example, using Strimzi, should work in a similar way. Other Kafka deployments, for example, using Strimzi, should work in a similar way.
*Please note that currently, even if installed differently, the corresponding services must run at *Please note that currently, even if installed differently, the corresponding services must run at
*my-confluent-cp-kafka:9092*, *my-confluent-cp-zookeeper:2181* and *my-confluent-cp-schema-registry:8081*. `my-confluent-cp-kafka:9092`, `my-confluent-cp-zookeeper:2181` and `my-confluent-cp-schema-registry:8081`.*
#### A Kafka Client Pod #### A Kafka Client Pod
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: scalability name: {{ template "theodolite.fullname" . }}-grafana-scalability
labels: labels:
grafana_dashboard: "1" grafana_dashboard: "1"
data: data:
......
...@@ -3,7 +3,7 @@ apiVersion: v1 ...@@ -3,7 +3,7 @@ apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
# name: {{ template "theodolite.fullname" . }}-kafka-client # name: {{ template "theodolite.fullname" . }}-kafka-client
name: kafka-client name: {{ template "theodolite.fullname" . }}-kafka-client
spec: spec:
containers: containers:
- name: kafka-client - name: kafka-client
......
...@@ -5,7 +5,7 @@ metadata: ...@@ -5,7 +5,7 @@ metadata:
labels: labels:
app: cp-kafka app: cp-kafka
appScope: titan-ccp appScope: titan-ccp
name: kafka name: {{ template "theodolite.fullname" . }}-cp-kafka
spec: spec:
selector: selector:
matchLabels: matchLabels:
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding kind: ClusterRoleBinding
metadata: metadata:
name: prometheus name: {{ template "theodolite.fullname" . }}-prometheus
roleRef: roleRef:
apiGroup: rbac.authorization.k8s.io apiGroup: rbac.authorization.k8s.io
kind: ClusterRole kind: ClusterRole
name: prometheus name: {{ template "theodolite.fullname" . }}-prometheus
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: prometheus name: {{ template "theodolite.fullname" . }}-prometheus
namespace: {{ .Release.Namespace }} namespace: {{ .Release.Namespace }}
{{- end}} {{- end}}
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole kind: ClusterRole
metadata: metadata:
name: prometheus name: {{ template "theodolite.fullname" . }}-prometheus
rules: rules:
- apiGroups: [""] - apiGroups: [""]
resources: resources:
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: prometheus name: {{ template "theodolite.fullname" . }}-prometheus
labels: labels:
grafana_datasource: "1" grafana_datasource: "1"
data: data:
......
...@@ -4,7 +4,7 @@ kind: Prometheus ...@@ -4,7 +4,7 @@ kind: Prometheus
metadata: metadata:
name: {{ template "theodolite.fullname" . }}-prometheus name: {{ template "theodolite.fullname" . }}-prometheus
spec: spec:
serviceAccountName: prometheus serviceAccountName: {{ template "theodolite.fullname" . }}-prometheus
serviceMonitorSelector: serviceMonitorSelector:
matchLabels: matchLabels:
#app: cp-kafka #app: cp-kafka
......
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
apiVersion: v1 apiVersion: v1
kind: ServiceAccount kind: ServiceAccount
metadata: metadata:
name: prometheus name: {{ template "theodolite.fullname" . }}-prometheus
{{- end}} {{- end}}
\ No newline at end of file
name: "Theodolite Test Context" name: example-execution
benchmark: "uc1-kstreams" benchmark: "uc1-kstreams"
load: load:
loadType: "NumSensors" loadType: "NumSensors"
...@@ -32,19 +32,19 @@ configOverrides: ...@@ -32,19 +32,19 @@ configOverrides:
resource: "uc1-kstreams-deployment.yaml" resource: "uc1-kstreams-deployment.yaml"
variableName: "env" variableName: "env"
value: "prod" value: "prod"
- patcher: # - patcher:
type: "ResourceLimitPatcher" # type: "ResourceLimitPatcher"
resource: "uc1-kstreams-deployment.yaml" # resource: "uc1-kstreams-deployment.yaml"
container: "uc-application" # container: "uc-application"
variableName: "cpu" # variableName: "cpu"
value: "1000m" # value: "1000m"
- patcher: # - patcher:
type: "ResourceLimitPatcher" # type: "ResourceLimitPatcher"
resource: "uc1-kstreams-deployment.yaml" # resource: "uc1-kstreams-deployment.yaml"
container: "uc-application" # container: "uc-application"
variableName: "memory" # variableName: "memory"
value: "2Gi" # value: "2Gi"
- patcher: # - patcher:
type: "SchedulerNamePatcher" # type: "SchedulerNamePatcher"
resource: "uc1-kstreams-deployment.yaml" # resource: "uc1-kstreams-deployment.yaml"
value: "random-scheduler" # value: "random-scheduler"
\ No newline at end of file
package theodolite.benchmark package theodolite.benchmark
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import io.fabric8.kubernetes.api.model.KubernetesResource
import io.fabric8.kubernetes.api.model.Namespaced
import io.fabric8.kubernetes.client.CustomResource
import io.quarkus.runtime.annotations.RegisterForReflection import io.quarkus.runtime.annotations.RegisterForReflection
import theodolite.util.ConfigurationOverride import theodolite.util.ConfigurationOverride
import kotlin.properties.Delegates import kotlin.properties.Delegates
@JsonDeserialize
@RegisterForReflection @RegisterForReflection
class BenchmarkExecution { class BenchmarkExecution : CustomResource(), Namespaced {
var executionId: Int = 0 var executionId: Int = 0
lateinit var name: String lateinit var name: String
lateinit var benchmark: String lateinit var benchmark: String
...@@ -15,16 +20,18 @@ class BenchmarkExecution { ...@@ -15,16 +20,18 @@ class BenchmarkExecution {
lateinit var execution: Execution lateinit var execution: Execution
lateinit var configOverrides: List<ConfigurationOverride?> lateinit var configOverrides: List<ConfigurationOverride?>
@JsonDeserialize
@RegisterForReflection @RegisterForReflection
class Execution { class Execution : KubernetesResource {
lateinit var strategy: String lateinit var strategy: String
var duration by Delegates.notNull<Long>() var duration by Delegates.notNull<Long>()
var repetitions by Delegates.notNull<Int>() var repetitions by Delegates.notNull<Int>()
lateinit var restrictions: List<String> lateinit var restrictions: List<String>
} }
@JsonDeserialize
@RegisterForReflection @RegisterForReflection
class Slo { class Slo : KubernetesResource {
lateinit var sloType: String lateinit var sloType: String
var threshold by Delegates.notNull<Int>() var threshold by Delegates.notNull<Int>()
lateinit var prometheusUrl: String lateinit var prometheusUrl: String
...@@ -33,14 +40,17 @@ class BenchmarkExecution { ...@@ -33,14 +40,17 @@ class BenchmarkExecution {
var warmup by Delegates.notNull<Int>() var warmup by Delegates.notNull<Int>()
} }
@JsonDeserialize
@RegisterForReflection @RegisterForReflection
class LoadDefinition { class LoadDefinition : KubernetesResource {
lateinit var loadType: String lateinit var loadType: String
lateinit var loadValues: List<Int> lateinit var loadValues: List<Int>
} }
@JsonDeserialize
@RegisterForReflection @RegisterForReflection
class ResourceDefinition { class ResourceDefinition : KubernetesResource {
lateinit var resourceType: String lateinit var resourceType: String
lateinit var resourceValues: List<Int> lateinit var resourceValues: List<Int>
} }
......
package theodolite.benchmark
import io.fabric8.kubernetes.client.CustomResourceList
class BenchmarkExecutionList : CustomResourceList<BenchmarkExecution>()
\ No newline at end of file
package theodolite.benchmark; package theodolite.benchmark
import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import mu.KotlinLogging import mu.KotlinLogging
......
package theodolite.benchmark package theodolite.benchmark
import io.fabric8.kubernetes.api.model.KubernetesResource import io.fabric8.kubernetes.api.model.KubernetesResource
import io.fabric8.kubernetes.api.model.Namespaced
import io.fabric8.kubernetes.client.CustomResource
import io.fabric8.kubernetes.client.DefaultKubernetesClient import io.fabric8.kubernetes.client.DefaultKubernetesClient
import io.quarkus.runtime.annotations.RegisterForReflection import io.quarkus.runtime.annotations.RegisterForReflection
import mu.KotlinLogging import mu.KotlinLogging
...@@ -9,11 +11,10 @@ import theodolite.patcher.PatcherFactory ...@@ -9,11 +11,10 @@ import theodolite.patcher.PatcherFactory
import theodolite.util.* import theodolite.util.*
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
private var DEFAULT_NAMESPACE = "default" private var DEFAULT_NAMESPACE = "default"
@RegisterForReflection @RegisterForReflection
class KubernetesBenchmark : Benchmark { class KubernetesBenchmark : Benchmark, CustomResource(), Namespaced {
lateinit var name: String lateinit var name: String
lateinit var appResource: List<String> lateinit var appResource: List<String>
lateinit var loadGenResource: List<String> lateinit var loadGenResource: List<String>
...@@ -24,12 +25,15 @@ class KubernetesBenchmark : Benchmark { ...@@ -24,12 +25,15 @@ class KubernetesBenchmark : Benchmark {
lateinit var path: String lateinit var path: String
private fun loadKubernetesResources(resources: List<String>): List<Pair<String, KubernetesResource>> { private fun loadKubernetesResources(resources: List<String>): List<Pair<String, KubernetesResource>> {
//val path = "./../../../resources/main/yaml/"
val parser = YamlParser() val parser = YamlParser()
namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE
logger.info { "Using $namespace as namespace." } logger.info { "Using $namespace as namespace." }
path = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
logger.info { "Using $path as path for resources." }
val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace(namespace)) val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace(namespace))
return resources return resources
.map { resource -> .map { resource ->
...@@ -58,7 +62,9 @@ class KubernetesBenchmark : Benchmark { ...@@ -58,7 +62,9 @@ class KubernetesBenchmark : Benchmark {
// Patch the given overrides // Patch the given overrides
configurationOverrides.forEach { override -> configurationOverrides.forEach { override ->
override?.let { patcherFactory.createPatcher(it.patcher, resources).patch(override.value) } override?.let {
patcherFactory.createPatcher(it.patcher, resources).patch(override.value)
}
} }
return KubernetesBenchmarkDeployment( return KubernetesBenchmarkDeployment(
......
package theodolite.benchmark
import io.fabric8.kubernetes.client.CustomResourceList
class KubernetesBenchmarkList : CustomResourceList<KubernetesBenchmark>()
\ No newline at end of file
...@@ -19,7 +19,7 @@ class AnalysisExecutor( ...@@ -19,7 +19,7 @@ class AnalysisExecutor(
offset = Duration.ofHours(slo.offset.toLong()) offset = Duration.ofHours(slo.offset.toLong())
) )
fun analyse(load: LoadDimension, res: Resource, executionDuration: Duration): Boolean { fun analyze(load: LoadDimension, res: Resource, executionDuration: Duration): Boolean {
var result = false var result = false
try { try {
......
...@@ -8,6 +8,7 @@ import theodolite.util.LoadDimension ...@@ -8,6 +8,7 @@ import theodolite.util.LoadDimension
import theodolite.util.Resource import theodolite.util.Resource
import theodolite.util.Results import theodolite.util.Results
import java.time.Duration import java.time.Duration
import java.util.concurrent.atomic.AtomicBoolean
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
...@@ -28,6 +29,8 @@ abstract class BenchmarkExecutor( ...@@ -28,6 +29,8 @@ abstract class BenchmarkExecutor(
val executionId: Int val executionId: Int
) { ) {
var run: AtomicBoolean = AtomicBoolean(true)
/** /**
* Run a experiment for the given parametrization, evaluate the experiment and save the result. * Run a experiment for the given parametrization, evaluate the experiment and save the result.
* *
...@@ -43,12 +46,19 @@ abstract class BenchmarkExecutor( ...@@ -43,12 +46,19 @@ abstract class BenchmarkExecutor(
*/ */
fun waitAndLog() { fun waitAndLog() {
logger.info { "Execution of a new benchmark started." } logger.info { "Execution of a new benchmark started." }
for (i in 1.rangeTo(executionDuration.toSeconds())) {
var secondsRunning = 0L
while (run.get() && secondsRunning < executionDuration.toSeconds()) {
secondsRunning++
Thread.sleep(Duration.ofSeconds(1).toMillis()) Thread.sleep(Duration.ofSeconds(1).toMillis())
if ((i % 60) == 0L) {
logger.info { "Executed: ${i / 60} minutes" } if ((secondsRunning % 60) == 0L) {
logger.info { "Executed: ${secondsRunning / 60} minutes." }
} }
} }
logger.debug { "Executor shutdown gracefully." }
} }
} }
...@@ -23,19 +23,24 @@ class BenchmarkExecutorImpl( ...@@ -23,19 +23,24 @@ class BenchmarkExecutorImpl(
executionId: Int executionId: Int
) : BenchmarkExecutor(benchmark, results, executionDuration, configurationOverrides, slo, executionId) { ) : BenchmarkExecutor(benchmark, results, executionDuration, configurationOverrides, slo, executionId) {
override fun runExperiment(load: LoadDimension, res: Resource): Boolean { override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
var result = false
val benchmarkDeployment = benchmark.buildDeployment(load, res, this.configurationOverrides) val benchmarkDeployment = benchmark.buildDeployment(load, res, this.configurationOverrides)
try {
benchmarkDeployment.setup() benchmarkDeployment.setup()
this.waitAndLog() this.waitAndLog()
} catch(e: Exception) {
logger.error { "Error while setup experiment." }
logger.error { "Error is: $e" }
this.run.set(false)
}
val result = AnalysisExecutor(slo = slo, executionId = executionId).analyse( if (this.run.get()) {
load = load, result =
res = res, AnalysisExecutor(slo = slo, executionId = executionId).analyze(load = load, res = res, executionDuration = executionDuration)
executionDuration = executionDuration
)
benchmarkDeployment.teardown()
this.results.setResult(Pair(load, res), result) this.results.setResult(Pair(load, res), result)
}
benchmarkDeployment.teardown()
return result return result
} }
} }
package theodolite.execution
import io.quarkus.runtime.annotations.QuarkusMain
import mu.KotlinLogging
import theodolite.execution.operator.TheodoliteOperator
import kotlin.system.exitProcess
private val logger = KotlinLogging.logger {}
@QuarkusMain
object Main {
@JvmStatic
fun main(args: Array<String>) {
val mode = System.getenv("MODE") ?: "operator"
logger.info { "Start Theodolite with mode $mode" }
when(mode) {
"yaml-executor" -> TheodoliteYamlExecutor().start()
"operator" -> TheodoliteOperator().start()
else -> {logger.error { "MODE $mode not found" }; exitProcess(1)}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment