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

Merge branch '164-restructure-patcher' into 'theodolite-kotlin'

Restructuring to create the PatcherDefinition inside the TheodoliteExecutor

See merge request !97
parents d4ead8a5 e7a2a0c5
No related branches found
No related tags found
4 merge requests!159Re-implementation of Theodolite with Kotlin/Quarkus,!157Update Graal Image in CI pipeline,!97Restructuring to create the PatcherDefinition inside the TheodoliteExecutor,!83WIP: Re-implementation of Theodolite with Kotlin/Quarkus
Pipeline #2376 passed
Showing
with 91 additions and 59 deletions
......@@ -4,7 +4,7 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
import io.fabric8.kubernetes.client.DefaultKubernetesClient
import mu.KotlinLogging
import theodolite.k8s.K8sResourceLoader
import theodolite.patcher.PatcherManager
import theodolite.patcher.PatcherFactory
import theodolite.util.*
private val logger = KotlinLogging.logger {}
......@@ -43,20 +43,15 @@ class KubernetesBenchmark : Benchmark {
configurationOverrides: List<ConfigurationOverride>
): BenchmarkDeployment {
val resources = loadKubernetesResources(this.appResource + this.loadGenResource)
val patcherManager = PatcherManager()
val patcherFactory = PatcherFactory()
// patch res and load
patcherManager.createAndApplyPatcher(res.getType(), this.resourceTypes, resources, res.get())
patcherManager.createAndApplyPatcher(load.getType(), this.loadTypes, resources, load.get().toString())
// patch the load dimension the resources
load.getType().forEach { patcherDefinition -> patcherFactory.createPatcher(patcherDefinition, resources).patch(load.get().toString()) }
res.getType().forEach{ patcherDefinition -> patcherFactory.createPatcher(patcherDefinition, resources).patch(res.get().toString()) }
// Patch the given overrides
configurationOverrides.forEach { override -> patcherFactory.createPatcher(override.patcher, resources).patch(override.value) }
// patch overrides
configurationOverrides.forEach { override ->
patcherManager.applyPatcher(
listOf(override.patcher),
resources,
override.value
)
}
return KubernetesBenchmarkDeployment(
namespace = namespace,
......
......@@ -2,6 +2,7 @@ package theodolite.execution
import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.KubernetesBenchmark
import theodolite.patcher.PatcherDefinitionFactory
import theodolite.strategies.StrategyFactory
import theodolite.strategies.searchstrategy.CompositeStrategy
import theodolite.util.Config
......@@ -20,6 +21,9 @@ class TheodoliteExecutor(
val strategyFactory = StrategyFactory()
val executionDuration = Duration.ofSeconds(config.execution.duration)
val resourcePatcherDefinition = PatcherDefinitionFactory().createPatcherDefinition(config.resources.resourceType, this.kubernetesBenchmark.resourceTypes)
val loadDimensionPatcherDefinition = PatcherDefinitionFactory().createPatcherDefinition(config.load.loadType, this.kubernetesBenchmark.loadTypes)
val executor =
BenchmarkExecutorImpl(
kubernetesBenchmark,
......@@ -30,9 +34,8 @@ class TheodoliteExecutor(
)
return Config(
loads = config.load.loadValues.map { load -> LoadDimension(load, config.load.loadType) },
resources = config.resources.resourceValues.map
{ resource -> Resource(resource, config.resources.resourceType) },
loads = config.load.loadValues.map { load -> LoadDimension(load, loadDimensionPatcherDefinition) },
resources = config.resources.resourceValues.map { resource -> Resource(resource, resourcePatcherDefinition) },
compositeStrategy = CompositeStrategy(
benchmarkExecutor = executor,
searchStrategy = strategyFactory.createSearchStrategy(executor, config.execution.strategy),
......
package theodolite.patcher
import theodolite.util.PatcherDefinition
import theodolite.util.TypeName
class PatcherDefinitionFactory {
fun createPatcherDefinition(requiredType: String, patcherTypes: List<TypeName>) : List<PatcherDefinition> {
return patcherTypes
.filter { type -> type.typeName == requiredType }
.flatMap { type -> type.patchers }
}
}
......@@ -2,13 +2,10 @@ package theodolite.patcher
import io.fabric8.kubernetes.api.model.KubernetesResource
import theodolite.util.PatcherDefinition
import theodolite.util.TypeName
class PatcherManager {
private fun createK8sPatcher(
patcherDefinition: PatcherDefinition,
k8sResources: List<Pair<String, KubernetesResource>>
): Patcher {
class PatcherFactory {
fun createPatcher(patcherDefinition: PatcherDefinition,
k8sResources: List<Pair<String, KubernetesResource>>) : Patcher {
val resource =
k8sResources.filter { it.first == patcherDefinition.resource }.map { resource -> resource.second }[0]
return when (patcherDefinition.type) {
......@@ -28,46 +25,4 @@ class PatcherManager {
else -> throw IllegalArgumentException("Patcher type ${patcherDefinition.type} not found")
}
}
private fun getPatcherDef(requiredType: String, patcherTypes: List<TypeName>): List<PatcherDefinition> {
return patcherTypes
.filter { type -> type.typeName == requiredType }
.flatMap { type -> type.patchers }
}
/**
* This function first creates a patcher definition and
* then patches the list of resources based on this patcher definition
*
* @param type Patcher type, for example "EnvVarPatcher"
* @param patcherTypes List of patcher types definitions, for example for resources and threads
* @param resources List of K8s resources, a patcher takes the resources that are needed
* @param value The value to patch
*/
fun createAndApplyPatcher(
type: String,
patcherTypes: List<TypeName>,
resources: List<Pair<String, KubernetesResource>>,
value: Any
) {
this.getPatcherDef(type, patcherTypes)
.forEach { patcherDef ->
createK8sPatcher(patcherDef, resources).patch(value)
}
}
/**
* Patch a resource based on the given patcher definition, a list of resources and a value to patch
*
* @param patcherDefinition The patcher definition
* @param resources List of patcher types definitions, for example for resources and threads
* @param value The value to patch
*/
fun applyPatcher(
patcherDefinition: List<PatcherDefinition>,
resources: List<Pair<String, KubernetesResource>>,
value: Any
) {
patcherDefinition.forEach { def -> this.createK8sPatcher(def, resources).patch(value) }
}
}
}
\ No newline at end of file
......@@ -13,7 +13,7 @@ import theodolite.util.Results
class LowerBoundRestriction(results: Results) : RestrictionStrategy(results) {
override fun next(load: LoadDimension, resources: List<Resource>): List<Resource> {
val maxLoad: LoadDimension? = this.results.getMaxBenchmarkedLoad(load)
var lowerBound: Resource? = this.results.getMinRequiredInstances(maxLoad, resources[0].getType())
var lowerBound: Resource? = this.results.getMinRequiredInstances(maxLoad)
if (lowerBound == null) {
lowerBound = resources[0]
}
......
package theodolite.util
data class LoadDimension(private val number: Int, private val type: String) {
data class LoadDimension(private val number: Int, private val type: List<PatcherDefinition>) {
fun get(): Int {
return this.number
}
fun getType(): String {
fun getType(): List<PatcherDefinition> {
return this.type
}
}
package theodolite.util
data class Resource(private val number: Int, private val type: String) {
data class Resource(private val number: Int, private val type: List<PatcherDefinition>) {
fun get(): Int {
return this.number
}
fun getType(): String {
fun getType(): List<PatcherDefinition> {
return this.type
}
}
......@@ -11,10 +11,10 @@ class Results {
return this.results[experiment]
}
fun getMinRequiredInstances(load: LoadDimension?, resourceTyp: String): Resource? {
if (this.results.isEmpty()) return Resource(Int.MIN_VALUE, resourceTyp)
fun getMinRequiredInstances(load: LoadDimension?): Resource? {
if (this.results.isEmpty()) return Resource(Int.MIN_VALUE, emptyList())
var requiredInstances: Resource? = Resource(Int.MAX_VALUE, resourceTyp)
var requiredInstances: Resource? = Resource(Int.MAX_VALUE, emptyList())
for (experiment in results) {
if (experiment.key.first == load && experiment.value) {
if (requiredInstances == null) {
......
......@@ -26,8 +26,8 @@ class CompositeStrategyTest {
arrayOf(false, false, false, false, false, false, true),
arrayOf(false, false, false, false, false, false, false)
)
val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, "NumSensors") }
val mockResources: List<Resource> = (0..6).map { number -> Resource(number, "Instances") }
val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
val results = Results()
val benchmark = TestBenchmark()
val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
......@@ -38,7 +38,7 @@ class CompositeStrategyTest {
CompositeStrategy(benchmarkExecutor, linearSearch, setOf(lowerBoundRestriction))
val actual: ArrayList<Resource?> = ArrayList()
val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, "Instances") })
val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, emptyList()) })
expected.add(null)
for (load in mockLoads) {
......@@ -59,8 +59,8 @@ class CompositeStrategyTest {
arrayOf(false, false, false, false, false, false, true),
arrayOf(false, false, false, false, false, false, false)
)
val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, "NumSensors") }
val mockResources: List<Resource> = (0..6).map { number -> Resource(number, "Instances") }
val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
val results = Results()
val benchmark = TestBenchmark()
val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
......@@ -72,7 +72,7 @@ class CompositeStrategyTest {
CompositeStrategy(benchmarkExecutorImpl, binarySearch, setOf(lowerBoundRestriction))
val actual: ArrayList<Resource?> = ArrayList()
val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, "Instances") })
val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, emptyList()) })
expected.add(null)
for (load in mockLoads) {
......@@ -93,8 +93,8 @@ class CompositeStrategyTest {
arrayOf(false, false, false, false, false, false, true, true),
arrayOf(false, false, false, false, false, false, false, true)
)
val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, "NumSensors") }
val mockResources: List<Resource> = (0..7).map { number -> Resource(number, "Instances") }
val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
val mockResources: List<Resource> = (0..7).map { number -> Resource(number, emptyList()) }
val results = Results()
val benchmark = TestBenchmark()
val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
......@@ -106,7 +106,7 @@ class CompositeStrategyTest {
val actual: ArrayList<Resource?> = ArrayList()
val expected: ArrayList<Resource?> =
ArrayList(listOf(0, 2, 2, 3, 4, 6, 7).map { x -> Resource(x, "Instances") })
ArrayList(listOf(0, 2, 2, 3, 4, 6, 7).map { x -> Resource(x, emptyList()) })
for (load in mockLoads) {
actual.add(strategy.findSuitableResource(load, mockResources))
......
......@@ -6,7 +6,7 @@ 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.patcher.PatcherManager
import theodolite.patcher.PatcherFactory
import theodolite.util.PatcherDefinition
/**
......@@ -23,7 +23,7 @@ import theodolite.util.PatcherDefinition
class ResourceLimitPatcherTest {
val testPath = "./src/main/resources/testYaml/"
val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace(""))
val manager = PatcherManager()
val patcherFactory = PatcherFactory()
fun applyTest(fileName: String) {
val cpuValue = "50m"
......@@ -42,20 +42,17 @@ class ResourceLimitPatcherTest {
defMEM.container = "uc-application"
defMEM.type = "ResourceLimitPatcher"
manager.applyPatcher(
patcherDefinition = listOf(defCPU),
resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)),
value = cpuValue
)
manager.applyPatcher(
patcherDefinition = listOf(defMEM),
resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)),
value = memValue
)
patcherFactory.createPatcher(
patcherDefinition = defCPU,
k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource))
).patch(value = cpuValue)
patcherFactory.createPatcher(
patcherDefinition = defMEM,
k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource))
).patch(value = memValue)
k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container }
.forEach {
println(it)
assertTrue(it.resources.limits["cpu"].toString() == cpuValue)
assertTrue(it.resources.limits["memory"].toString() == memValue)
}
......
......@@ -6,7 +6,7 @@ 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.patcher.PatcherManager
import theodolite.patcher.PatcherFactory
import theodolite.util.PatcherDefinition
/**
......@@ -23,7 +23,7 @@ import theodolite.util.PatcherDefinition
class ResourceRequestPatcherTest {
val testPath = "./src/main/resources/testYaml/"
val loader = K8sResourceLoader(DefaultKubernetesClient().inNamespace(""))
val manager = PatcherManager()
val patcherFactory = PatcherFactory()
fun applyTest(fileName: String) {
val cpuValue = "50m"
......@@ -42,20 +42,17 @@ class ResourceRequestPatcherTest {
defMEM.container = "uc-application"
defMEM.type = "ResourceRequestPatcher"
manager.applyPatcher(
patcherDefinition = listOf(defCPU),
resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)),
value = cpuValue
)
manager.applyPatcher(
patcherDefinition = listOf(defMEM),
resources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource)),
value = memValue
)
patcherFactory.createPatcher(
patcherDefinition = defCPU,
k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource))
).patch(value = cpuValue)
patcherFactory.createPatcher(
patcherDefinition = defMEM,
k8sResources = listOf(Pair("cpu-memory-deployment.yaml", k8sResource))
).patch(value = memValue)
k8sResource.spec.template.spec.containers.filter { it.name == defCPU.container }
.forEach {
println(it)
assertTrue(it.resources.requests["cpu"].toString() == cpuValue)
assertTrue(it.resources.requests["memory"].toString() == memValue)
}
......
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