diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index fc60fc6f6fddbb9b18a85ed1f472a444e0ed4cea..4acb2ba79d5cde699cf9dd4d379bf17c3c93e068 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -239,7 +239,7 @@ GEM jekyll-seo-tag (~> 2.1) minitest (5.15.0) multipart-post (2.1.1) - nokogiri (1.13.4-x86_64-linux) + nokogiri (1.13.6-x86_64-linux) racc (~> 1.4) octokit (4.22.0) faraday (>= 0.9) diff --git a/docs/api-reference/crds.md b/docs/api-reference/crds.md index fb3f02ac941870dd085d06027d972e6003c7aadb..c5cc7596f4c23408597f48b366f6b97e889e7a66 100644 --- a/docs/api-reference/crds.md +++ b/docs/api-reference/crds.md @@ -146,6 +146,15 @@ Resource Types: <i>Default</i>: <br/> </td> <td>false</td> + </tr><tr> + <td><b>waitForResourcesEnabled</b></td> + <td>boolean</td> + <td> + If true, Theodolite waits to create the resource for the SUT until the infrastructure resources are ready, and analogously, Theodolite waits to create the load-gen resource until the resources of the SUT are ready.<br/> + <br/> + <i>Default</i>: false<br/> + </td> + <td>false</td> </tr></tbody> </table> diff --git a/docs/index.yaml b/docs/index.yaml index c6cf4f6dcbeaf4b4ede37bca925025db950a2a77..956bb83b19ebbae4cddc4da6f07a0d937cf3dc2d 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -1,41 +1,6 @@ apiVersion: v1 entries: theodolite: - - apiVersion: v2 - appVersion: 0.7.0 - created: "2022-05-11T13:49:02.457130925+02:00" - dependencies: - - condition: grafana.enabled - name: grafana - repository: https://grafana.github.io/helm-charts - version: 6.17.5 - - condition: kube-prometheus-stack.enabled - name: kube-prometheus-stack - repository: https://prometheus-community.github.io/helm-charts - version: 20.0.1 - - condition: cp-helm-charts.enabled - name: cp-helm-charts - repository: https://soerenhenning.github.io/cp-helm-charts - version: 0.6.0 - - condition: strimzi.enabled - name: strimzi-kafka-operator - repository: https://strimzi.io/charts/ - version: 0.28.0 - description: Theodolite is a framework for benchmarking the horizontal and vertical - scalability of cloud-native applications. - digest: af10134baa30bb07423f78240fe1c609381e1c616585883cf5d3aded2d86a2b1 - home: https://www.theodolite.rocks - maintainers: - - email: soeren.henning@email.uni-kiel.de - name: Sören Henning - url: https://www.se.informatik.uni-kiel.de/en/team/soeren-henning-m-sc - name: theodolite - sources: - - https://github.com/cau-se/theodolite - type: application - urls: - - https://github.com/cau-se/theodolite/releases/download/v0.7.0/theodolite-0.7.0%20copy.tgz - version: 0.7.0 - apiVersion: v2 appVersion: 0.7.0 created: "2022-05-11T13:49:02.491041789+02:00" diff --git a/theodolite/crd/crd-benchmark.yaml b/theodolite/crd/crd-benchmark.yaml index c901e61360c05b2f1cf2b1767a20f624eb262231..d2418ee005e2c0168254a9423b9c383ace2d3ca7 100644 --- a/theodolite/crd/crd-benchmark.yaml +++ b/theodolite/crd/crd-benchmark.yaml @@ -26,6 +26,10 @@ spec: description: This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten. type: string default: "" + waitForResourcesEnabled: + description: If true, Theodolite waits to create the resource for the SUT until the infrastructure resources are ready, and analogously, Theodolite waits to create the load-gen resource until the resources of the SUT are ready. + type: boolean + default: false infrastructure: description: (Optional) A list of file names that reference Kubernetes resources that are deployed on the cluster to create the required infrastructure. type: object diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt index 272da07e9f8edab6200dea47725b65829178d9bc..ddb83c54c7845651754ae82c9abf8780c77fdba1 100644 --- a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt +++ b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt @@ -11,6 +11,7 @@ import theodolite.k8s.K8sManager import theodolite.patcher.PatchHandler import theodolite.patcher.PatcherFactory import theodolite.util.* +import kotlin.properties.Delegates private val logger = KotlinLogging.logger {} @@ -38,6 +39,7 @@ private var DEFAULT_THEODOLITE_APP_RESOURCES = "./benchmark-resources" @RegisterForReflection class KubernetesBenchmark : KubernetesResource, Benchmark { lateinit var name: String + var waitForResourcesEnabled = false lateinit var resourceTypes: List<TypeName> lateinit var loadTypes: List<TypeName> var kafkaConfig: KafkaConfig? = null @@ -65,11 +67,8 @@ class KubernetesBenchmark : KubernetesResource, Benchmark { override fun setupInfrastructure() { this.infrastructure.beforeActions.forEach { it.exec(client = client) } - val kubernetesManager = K8sManager(this.client) - - loadResources(this.infrastructure.resources) - .map { it.second } - .forEach { kubernetesManager.deploy(it) } + RolloutManager(waitForResourcesEnabled, this.client) + .rollout(loadResources(this.infrastructure.resources).map { it.second }) } override fun teardownInfrastructure() { @@ -138,7 +137,9 @@ class KubernetesBenchmark : KubernetesResource, Benchmark { afterTeardownDelay = afterTeardownDelay, kafkaConfig = if (kafkaConfig != null) mapOf("bootstrap.servers" to kafkaConfig.bootstrapServer) else mapOf(), topics = kafkaConfig?.topics ?: listOf(), - client = this.client + client = this.client, + rolloutMode = waitForResourcesEnabled + ) } diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt index b30032c524b1e421301e0e9d1ffe83772b43d900..1d7b22233c084625cf16ca7194c76c14601bbaad 100644 --- a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt +++ b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt @@ -28,6 +28,7 @@ class KubernetesBenchmarkDeployment( private val sutAfterActions: List<Action>, private val loadGenBeforeActions: List<Action>, private val loadGenAfterActions: List<Action>, + private val rolloutMode: Boolean, val appResources: List<HasMetadata>, val loadGenResources: List<HasMetadata>, private val loadGenerationDelay: Long, @@ -47,19 +48,20 @@ class KubernetesBenchmarkDeployment( * - Deploy the needed resources. */ override fun setup() { + val rolloutManager = RolloutManager(rolloutMode, client) if (this.topics.isNotEmpty()) { val kafkaTopics = this.topics .filter { !it.removeOnly } .map { NewTopic(it.name, it.numPartitions, it.replicationFactor) } kafkaController.createTopics(kafkaTopics) } + sutBeforeActions.forEach { it.exec(client = client) } - appResources.forEach { kubernetesManager.deploy(it) } + rolloutManager.rollout(appResources) logger.info { "Wait ${this.loadGenerationDelay} seconds before starting the load generator." } Thread.sleep(Duration.ofSeconds(this.loadGenerationDelay).toMillis()) loadGenBeforeActions.forEach { it.exec(client = client) } - loadGenResources.forEach { kubernetesManager.deploy(it) } - + rolloutManager.rollout(loadGenResources) } /** diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/RolloutManager.kt b/theodolite/src/main/kotlin/theodolite/benchmark/RolloutManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..f282fb27971218754a0e35801342efc83837b64b --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/RolloutManager.kt @@ -0,0 +1,42 @@ +package theodolite.benchmark + +import io.fabric8.kubernetes.api.model.HasMetadata +import io.fabric8.kubernetes.api.model.Pod +import io.fabric8.kubernetes.api.model.apps.DaemonSet +import io.fabric8.kubernetes.api.model.apps.Deployment +import io.fabric8.kubernetes.api.model.apps.ReplicaSet +import io.fabric8.kubernetes.api.model.apps.StatefulSet +import io.fabric8.kubernetes.api.model.batch.v1.Job +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import theodolite.k8s.K8sManager + +private var SLEEP_TIME_MS = 500L + + +class RolloutManager(private val blockUntilResourcesReady: Boolean, private val client: NamespacedKubernetesClient) { + + fun rollout(resources: List<HasMetadata>) { + resources + .forEach { K8sManager(client).deploy(it) } + + if (blockUntilResourcesReady) { + resources + .forEach { + when (it) { + is Deployment -> waitFor { client.apps().deployments().withName(it.metadata.name).isReady } + is StatefulSet -> waitFor { client.apps().statefulSets().withName(it.metadata.name).isReady } + is DaemonSet -> waitFor { client.apps().daemonSets().withName(it.metadata.name).isReady } + is ReplicaSet -> waitFor { client.apps().replicaSets().withName(it.metadata.name).isReady } + is Job -> waitFor { client.batch().v1().cronjobs().withName(it.metadata.name).isReady } + } + } + } + } + + private fun waitFor(isResourceReady: () -> Boolean) { + while (!isResourceReady()) { + Thread.sleep(SLEEP_TIME_MS) + } + } + +} \ No newline at end of file diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt index cbddbfbfc5d6f838677c6d04b0a0c79f59d8bc66..d6841429166d1549e84ad27887fbf0cba86b174d 100644 --- a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt +++ b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt @@ -20,11 +20,12 @@ class BenchmarkCRDummy(name: String) { kafkaConfig.bootstrapServer = "" kafkaConfig.topics = emptyList() + benchmarkCR.spec = benchmark benchmarkCR.metadata.name = name benchmarkCR.kind = "Benchmark" benchmarkCR.apiVersion = "v1" - + benchmark.waitForResourcesEnabled = false benchmark.infrastructure = Resources() benchmark.sut = Resources() diff --git a/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml b/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml index ea9ee8471d3da1dc6011348bd978696bd0fa6f36..102a6a249ab06301396eaf375e7bd2590b334b22 100644 --- a/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml +++ b/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml @@ -3,6 +3,7 @@ kind: benchmark metadata: name: example-benchmark spec: + waitForResourcesEnabled: false sut: resources: - configMap: