diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt index 8fc951d09598187bcaf4cb7e4a39d322be722792..b4259003e96855fe57e5117978064447995d4f83 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/execution/operator/ClusterSetup.kt @@ -4,9 +4,9 @@ import io.fabric8.kubernetes.client.NamespacedKubernetesClient import io.fabric8.kubernetes.client.dsl.MixedOperation import io.fabric8.kubernetes.client.dsl.Resource import mu.KotlinLogging -import org.json.JSONObject import theodolite.execution.Shutdown import theodolite.k8s.K8sContextFactory +import theodolite.k8s.ResourceByLabelHandler import theodolite.model.crd.* private val logger = KotlinLogging.logger {} @@ -29,9 +29,15 @@ class ClusterSetup( clearByLabel() } + /** + * This function searches for executions in the cluster that have the status running and tries to stop the execution. + * For this the corresponding benchmark is searched and terminated. + * + * Throws [IllegalStateException] if no suitable benchmark can be found. + * + */ private fun stopRunningExecution() { executionCRDClient - .inNamespace(client.namespace) .list() .items .asSequence() @@ -51,26 +57,33 @@ class ClusterSetup( logger.error { "Execution with state ${States.RUNNING.value} was found, but no corresponding benchmark. " + "Could not initialize cluster." } + throw IllegalStateException("Cluster state is invalid, required Benchmark for running execution not found.") } - - } } private fun clearByLabel() { - this.client.services().withLabel("app.kubernetes.io/created-by=theodolite").delete() - this.client.apps().deployments().withLabel("app.kubernetes.io/created-by=theodolite").delete() - this.client.apps().statefulSets().withLabel("app.kubernetes.io/created-by=theodolite").delete() - this.client.configMaps().withLabel("app.kubernetes.io/created-by=theodolite").delete() - - val serviceMonitors = JSONObject( - this.client.customResource(serviceMonitorContext) - .list(client.namespace, mapOf(Pair("app.kubernetes.io/created-by", "theodolite"))) + val resourceRemover = ResourceByLabelHandler(client = client) + resourceRemover.removeServices( + labelName = "app.kubernetes.io/created-by", + labelValue = "theodolite" + ) + resourceRemover.removeDeployments( + labelName = "app.kubernetes.io/created-by", + labelValue = "theodolite" + ) + resourceRemover.removeStatefulSets( + labelName = "app.kubernetes.io/created-by", + labelValue = "theodolite" + ) + resourceRemover.removeConfigMaps( + labelName = "app.kubernetes.io/created-by", + labelValue = "theodolite" + ) + resourceRemover.removeCR( + labelName = "app.kubernetes.io/created-by", + labelValue = "theodolite", + context = serviceMonitorContext ) - .getJSONArray("items") - - (0 until serviceMonitors.length()) - .map { serviceMonitors.getJSONObject(it).getJSONObject("metadata").getString("name") } - .forEach { this.client.customResource(serviceMonitorContext).delete(client.namespace, it) } } } \ No newline at end of file diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sManager.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sManager.kt index 77350868500ffa974ab2b9fadfb8cfd915c8aaf2..abeb1c514d100fc3a12bd8f210e89d65eff9b2cf 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sManager.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sManager.kt @@ -43,9 +43,12 @@ class K8sManager(private val client: NamespacedKubernetesClient) { fun remove(resource: KubernetesResource) { when (resource) { is Deployment -> { - val label = resource.spec.selector.matchLabels["app"]!! this.client.apps().deployments().delete(resource) - blockUntilPodsDeleted(label) + ResourceByLabelHandler(client = client) + .blockUntilPodsDeleted( + labelName = "app", + labelValue = resource.spec.selector.matchLabels["app"]!! + ) logger.info { "Deployment '${resource.metadata.name}' deleted." } } is Service -> @@ -53,21 +56,16 @@ class K8sManager(private val client: NamespacedKubernetesClient) { is ConfigMap -> this.client.configMaps().delete(resource) is StatefulSet -> { - val label = resource.spec.selector.matchLabels["app"]!! this.client.apps().statefulSets().delete(resource) - blockUntilPodsDeleted(label) + ResourceByLabelHandler(client = client) + .blockUntilPodsDeleted( + labelName = "app", + labelValue = resource.spec.selector.matchLabels["app"]!! + ) logger.info { "StatefulSet '$resource.metadata.name' deleted." } } is CustomResourceWrapper -> resource.delete(client) else -> throw IllegalArgumentException("Unknown Kubernetes resource.") } } - - private fun blockUntilPodsDeleted(podLabel: String) { - while (!this.client.pods().withLabel(podLabel).list().items.isNullOrEmpty()) { - logger.info { "Wait for pods with label '$podLabel' to be deleted." } - Thread.sleep(1000) - } - } - } diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ResourceByLabelHandler.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ResourceByLabelHandler.kt index be0247d5b0351d2c7acec84d5bdad99376f7d9a7..c0be6f25ab18e62fd90fccdb75396da012da2223 100644 --- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ResourceByLabelHandler.kt +++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ResourceByLabelHandler.kt @@ -8,22 +8,28 @@ import org.json.JSONObject private val logger = KotlinLogging.logger {} /** - * Used to reset the KafkaLagExporter by deleting the pod. + * The ResourceByLabelHandler provides basic functions to manage Kubernetes resources through their labels. * @param client NamespacedKubernetesClient used for the deletion. */ -// TODO(Maybe we can add support to delete arbitrary resources (kinds), -// then we can use this class also inside the ClusterSetup class instead of the clearByLabel function.) -class ResourceByLabelRemover(private val client: NamespacedKubernetesClient) { +class ResourceByLabelHandler(private val client: NamespacedKubernetesClient) { /** * Deletes all pods with the selected label. - * @param [label] of the pod that should be deleted. + * @param [labelName] the label name + * @param [labelValue] the value of this label */ - fun removePods(label: String) { - this.client.pods().withLabel(label).delete() - logger.info { "Pod with label: $label deleted" } + fun removePods(labelName: String, labelValue: String) { + this.client + .pods() + .withLabel("$labelName=$labelValue").delete() + logger.info { "Pod with label: $labelName=$labelValue deleted" } } + /** + * Deletes all services with the selected label. + * @param [labelName] the label name + * @param [labelValue] the value of this label + */ fun removeServices(labelName: String, labelValue: String) { this.client .services() @@ -31,6 +37,11 @@ class ResourceByLabelRemover(private val client: NamespacedKubernetesClient) { .delete() } + /** + * Deletes all deployments with the selected label. + * @param [labelName] the label name + * @param [labelValue] the value of this label + */ fun removeDeployments(labelName: String, labelValue: String){ this.client .apps() @@ -39,7 +50,13 @@ class ResourceByLabelRemover(private val client: NamespacedKubernetesClient) { .delete() } - fun removeStateFulSets(labelName: String, labelValue: String) { + + /** + * Deletes all stateful sets with the selected label. + * @param [labelName] the label name + * @param [labelValue] the value of this label + */ + fun removeStatefulSets(labelName: String, labelValue: String) { this.client .apps() .statefulSets() @@ -47,6 +64,11 @@ class ResourceByLabelRemover(private val client: NamespacedKubernetesClient) { .delete() } + /** + * Deletes all configmaps with the selected label. + * @param [labelName] the label name + * @param [labelValue] the value of this label + */ fun removeConfigMaps(labelName: String, labelValue: String){ this.client .configMaps() @@ -54,6 +76,11 @@ class ResourceByLabelRemover(private val client: NamespacedKubernetesClient) { .delete() } + /** + * Deletes all custom resources sets with the selected label. + * @param [labelName] the label name + * @param [labelValue] the value of this label + */ fun removeCR(labelName: String, labelValue: String, context: CustomResourceDefinitionContext) { val customResources = JSONObject( this.client.customResource(context) @@ -65,4 +92,23 @@ class ResourceByLabelRemover(private val client: NamespacedKubernetesClient) { .map { customResources.getJSONObject(it).getJSONObject("metadata").getString("name") } .forEach { this.client.customResource(context).delete(client.namespace, it) } } + + /** + * Block until all pods with are deleted + * + * @param [labelName] the label name + * @param [labelValue] the value of this label + * */ + fun blockUntilPodsDeleted(labelName: String, labelValue: String) { + while ( + !this.client + .pods() + .withLabel("$labelName=$labelValue") + .list() + .items + .isNullOrEmpty()) { + logger.info { "Wait for pods with label $labelName=$labelValue to be deleted." } + Thread.sleep(1000) + } + } }