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
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