Skip to content
Snippets Groups Projects
Commit 67e93b03 authored by Sören Henning's avatar Sören Henning
Browse files

Merge branch 'master' into wetzel/spesb-249-make-analysis-flexible

parents c864b285 3b365db9
No related branches found
No related tags found
1 merge request!180Make the analysis of experiments more flexible
This commit is part of merge request !180. Comments created here will be created in the context of that merge request.
Showing
with 146 additions and 16 deletions
...@@ -29,7 +29,8 @@ abstract class BenchmarkExecutor( ...@@ -29,7 +29,8 @@ abstract class BenchmarkExecutor(
val repetitions: Int, val repetitions: Int,
val executionId: Int, val executionId: Int,
val loadGenerationDelay: Long, val loadGenerationDelay: Long,
val afterTeardownDelay: Long val afterTeardownDelay: Long,
val executionName: String
) { ) {
var run: AtomicBoolean = AtomicBoolean(true) var run: AtomicBoolean = AtomicBoolean(true)
......
...@@ -5,6 +5,7 @@ import mu.KotlinLogging ...@@ -5,6 +5,7 @@ import mu.KotlinLogging
import theodolite.benchmark.Benchmark import theodolite.benchmark.Benchmark
import theodolite.benchmark.BenchmarkExecution import theodolite.benchmark.BenchmarkExecution
import theodolite.evaluation.AnalysisExecutor import theodolite.evaluation.AnalysisExecutor
import theodolite.execution.operator.EventCreator
import theodolite.util.* import theodolite.util.*
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant
...@@ -21,7 +22,8 @@ class BenchmarkExecutorImpl( ...@@ -21,7 +22,8 @@ class BenchmarkExecutorImpl(
repetitions: Int, repetitions: Int,
executionId: Int, executionId: Int,
loadGenerationDelay: Long, loadGenerationDelay: Long,
afterTeardownDelay: Long afterTeardownDelay: Long,
executionName: String
) : BenchmarkExecutor( ) : BenchmarkExecutor(
benchmark, benchmark,
results, results,
...@@ -31,15 +33,19 @@ class BenchmarkExecutorImpl( ...@@ -31,15 +33,19 @@ class BenchmarkExecutorImpl(
repetitions, repetitions,
executionId, executionId,
loadGenerationDelay, loadGenerationDelay,
afterTeardownDelay afterTeardownDelay,
executionName
) { ) {
private val eventCreator = EventCreator()
private val mode = Configuration.EXECUTION_MODE
override fun runExperiment(load: LoadDimension, res: Resource): Boolean { override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
var result = false var result = false
val executionIntervals: MutableList<Pair<Instant, Instant>> = ArrayList() val executionIntervals: MutableList<Pair<Instant, Instant>> = ArrayList()
for (i in 1.rangeTo(repetitions)) { for (i in 1.rangeTo(repetitions)) {
logger.info { "Run repetition $i/$repetitions" }
if (this.run.get()) { if (this.run.get()) {
logger.info { "Run repetition $i/$repetitions" }
executionIntervals.add(runSingleExperiment(load, res)) executionIntervals.add(runSingleExperiment(load, res))
} else { } else {
break break
...@@ -83,14 +89,43 @@ class BenchmarkExecutorImpl( ...@@ -83,14 +89,43 @@ class BenchmarkExecutorImpl(
try { try {
benchmarkDeployment.setup() benchmarkDeployment.setup()
this.waitAndLog() 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) { } catch (e: Exception) {
this.run.set(false) 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) throw ExecutionFailedException("Error during setup the experiment", e)
} }
val to = Instant.now() val to = Instant.now()
try { try {
benchmarkDeployment.teardown() benchmarkDeployment.teardown()
if (mode == ExecutionModes.OPERATOR.value) {
eventCreator.createEvent(
executionName = executionName,
type = "NORMAL",
reason = "Stop experiment",
message = "Teardown complete")
}
} catch (e: Exception) { } catch (e: Exception) {
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) throw ExecutionFailedException("Error during teardown the experiment", e)
} }
return Pair(from, to) return Pair(from, to)
......
package theodolite.execution
enum class ExecutionModes(val value: String) {
OPERATOR("operator"),
YAML_EXECUTOR("yaml-executor"),
STANDALONE("standalone")
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ package theodolite.execution ...@@ -3,6 +3,7 @@ package theodolite.execution
import io.quarkus.runtime.annotations.QuarkusMain import io.quarkus.runtime.annotations.QuarkusMain
import mu.KotlinLogging import mu.KotlinLogging
import theodolite.execution.operator.TheodoliteOperator import theodolite.execution.operator.TheodoliteOperator
import theodolite.util.Configuration
import kotlin.system.exitProcess import kotlin.system.exitProcess
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
...@@ -13,13 +14,12 @@ object Main { ...@@ -13,13 +14,12 @@ object Main {
@JvmStatic @JvmStatic
fun main(args: Array<String>) { fun main(args: Array<String>) {
val mode = System.getenv("MODE") ?: "standalone" val mode = Configuration.EXECUTION_MODE
logger.info { "Start Theodolite with mode $mode" } logger.info { "Start Theodolite with mode $mode" }
when (mode) { when (mode.toLowerCase()) {
"standalone" -> TheodoliteStandalone().start() ExecutionModes.STANDALONE.value, ExecutionModes.YAML_EXECUTOR.value -> TheodoliteStandalone().start() // TODO remove standalone (#209)
"yaml-executor" -> TheodoliteStandalone().start() // TODO remove (#209) ExecutionModes.OPERATOR.value -> TheodoliteOperator().start()
"operator" -> TheodoliteOperator().start()
else -> { else -> {
logger.error { "MODE $mode not found" } logger.error { "MODE $mode not found" }
exitProcess(1) exitProcess(1)
......
...@@ -65,7 +65,8 @@ class TheodoliteExecutor( ...@@ -65,7 +65,8 @@ class TheodoliteExecutor(
repetitions = config.execution.repetitions, repetitions = config.execution.repetitions,
executionId = config.executionId, executionId = config.executionId,
loadGenerationDelay = config.execution.loadGenerationDelay, loadGenerationDelay = config.execution.loadGenerationDelay,
afterTeardownDelay = config.execution.afterTeardownDelay afterTeardownDelay = config.execution.afterTeardownDelay,
executionName = config.name
) )
if (config.load.loadValues != config.load.loadValues.sorted()) { if (config.load.loadValues != config.load.loadValues.sorted()) {
......
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
...@@ -5,6 +5,7 @@ import io.fabric8.kubernetes.client.dsl.Resource ...@@ -5,6 +5,7 @@ import io.fabric8.kubernetes.client.dsl.Resource
import mu.KotlinLogging import mu.KotlinLogging
import theodolite.benchmark.BenchmarkExecution import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.KubernetesBenchmark import theodolite.benchmark.KubernetesBenchmark
import theodolite.execution.ExecutionModes
import theodolite.execution.TheodoliteExecutor import theodolite.execution.TheodoliteExecutor
import theodolite.model.crd.* import theodolite.model.crd.*
import theodolite.patcher.ConfigOverrideModifier import theodolite.patcher.ConfigOverrideModifier
...@@ -101,6 +102,11 @@ class TheodoliteController( ...@@ -101,6 +102,11 @@ class TheodoliteController(
} }
} }
} catch (e: Exception) { } 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 { "Failure while executing execution ${execution.name} with benchmark ${benchmark.name}." }
logger.error { "Problem is: $e" } logger.error { "Problem is: $e" }
executionStateHandler.setExecutionState(execution.name, States.FAILURE) executionStateHandler.setExecutionState(execution.name, States.FAILURE)
......
...@@ -11,6 +11,7 @@ import theodolite.model.crd.BenchmarkCRD ...@@ -11,6 +11,7 @@ import theodolite.model.crd.BenchmarkCRD
import theodolite.model.crd.BenchmarkExecutionList import theodolite.model.crd.BenchmarkExecutionList
import theodolite.model.crd.ExecutionCRD import theodolite.model.crd.ExecutionCRD
import theodolite.model.crd.KubernetesBenchmarkList import theodolite.model.crd.KubernetesBenchmarkList
import theodolite.util.Configuration
private const val DEFAULT_NAMESPACE = "default" private const val DEFAULT_NAMESPACE = "default"
...@@ -27,7 +28,7 @@ private val logger = KotlinLogging.logger {} ...@@ -27,7 +28,7 @@ private val logger = KotlinLogging.logger {}
* **See Also:** [Kubernetes Operator Pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) * **See Also:** [Kubernetes Operator Pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)
*/ */
class TheodoliteOperator { class TheodoliteOperator {
private val namespace = System.getenv("NAMESPACE") ?: DEFAULT_NAMESPACE private val namespace = Configuration.NAMESPACE
private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace) private val client: NamespacedKubernetesClient = DefaultKubernetesClient().inNamespace(namespace)
private lateinit var controller: TheodoliteController private lateinit var controller: TheodoliteController
...@@ -37,7 +38,7 @@ class TheodoliteOperator { ...@@ -37,7 +38,7 @@ class TheodoliteOperator {
fun start() { fun start() {
LeaderElector( LeaderElector(
client = client, client = client,
name = "theodolite-operator" // TODO(make leaslock name configurable via env var) name = Configuration.COMPONENT_NAME
) )
.getLeadership(::startOperator) .getLeadership(::startOperator)
} }
...@@ -115,7 +116,7 @@ class TheodoliteOperator { ...@@ -115,7 +116,7 @@ class TheodoliteOperator {
return this.controller return this.controller
} }
private fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation< fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation<
ExecutionCRD, ExecutionCRD,
BenchmarkExecutionList, BenchmarkExecutionList,
Resource<ExecutionCRD>> { Resource<ExecutionCRD>> {
......
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
}
}
...@@ -26,7 +26,8 @@ class TestBenchmarkExecutorImpl( ...@@ -26,7 +26,8 @@ class TestBenchmarkExecutorImpl(
repetitions = 1, repetitions = 1,
executionId = executionId, executionId = executionId,
loadGenerationDelay = loadGenerationDelay, loadGenerationDelay = loadGenerationDelay,
afterTeardownDelay = afterTeardownDelay afterTeardownDelay = afterTeardownDelay,
executionName = "test-execution"
) { ) {
override fun runExperiment(load: LoadDimension, res: Resource): Boolean { override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment