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
......@@ -32,4 +32,4 @@ spec:
numPartitions: 40
replicationFactor: 1
- name: "theodolite-.*"
removeOnly: True
\ No newline at end of file
removeOnly: True
......@@ -29,7 +29,8 @@ abstract class BenchmarkExecutor(
val repetitions: Int,
val executionId: Int,
val loadGenerationDelay: Long,
val afterTeardownDelay: Long
val afterTeardownDelay: Long,
val executionName: String
) {
var run: AtomicBoolean = AtomicBoolean(true)
......
......@@ -5,6 +5,7 @@ import mu.KotlinLogging
import theodolite.benchmark.Benchmark
import theodolite.benchmark.BenchmarkExecution
import theodolite.evaluation.AnalysisExecutor
import theodolite.execution.operator.EventCreator
import theodolite.util.*
import java.time.Duration
import java.time.Instant
......@@ -21,7 +22,8 @@ class BenchmarkExecutorImpl(
repetitions: Int,
executionId: Int,
loadGenerationDelay: Long,
afterTeardownDelay: Long
afterTeardownDelay: Long,
executionName: String
) : BenchmarkExecutor(
benchmark,
results,
......@@ -31,15 +33,19 @@ class BenchmarkExecutorImpl(
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
......@@ -83,16 +89,45 @@ class BenchmarkExecutorImpl(
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) {
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) {
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
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
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)
......
......@@ -65,7 +65,8 @@ class TheodoliteExecutor(
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()) {
......
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
import mu.KotlinLogging
import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.KubernetesBenchmark
import theodolite.execution.ExecutionModes
import theodolite.execution.TheodoliteExecutor
import theodolite.model.crd.*
import theodolite.patcher.ConfigOverrideModifier
......@@ -101,6 +102,11 @@ class TheodoliteController(
}
}
} 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)
......
......@@ -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,7 +28,7 @@ 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
......@@ -37,7 +38,7 @@ class TheodoliteOperator {
fun start() {
LeaderElector(
client = client,
name = "theodolite-operator" // TODO(make leaslock name configurable via env var)
name = Configuration.COMPONENT_NAME
)
.getLeadership(::startOperator)
}
......@@ -115,7 +116,7 @@ class TheodoliteOperator {
return this.controller
}
private fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation<
fun getExecutionClient(client: NamespacedKubernetesClient): MixedOperation<
ExecutionCRD,
BenchmarkExecutionList,
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(
repetitions = 1,
executionId = executionId,
loadGenerationDelay = loadGenerationDelay,
afterTeardownDelay = afterTeardownDelay
afterTeardownDelay = afterTeardownDelay,
executionName = "test-execution"
) {
override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment