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

Merge branch '203-add-support-for-service-monitors' into 'theodolite-kotlin'

Add support for  ServiceMonitors

See merge request !120
parents 85430ede c76b3e4b
No related branches found
No related tags found
4 merge requests!159Re-implementation of Theodolite with Kotlin/Quarkus,!157Update Graal Image in CI pipeline,!120Add support for ServiceMonitors,!83WIP: Re-implementation of Theodolite with Kotlin/Quarkus
Pipeline #2716 passed
...@@ -23,4 +23,4 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b ...@@ -23,4 +23,4 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b
deployment.teardown() deployment.teardown()
logger.info { "Teardown completed" } logger.info { "Teardown completed" }
} }
} }
\ No newline at end of file
...@@ -28,13 +28,15 @@ class TheodoliteYamlExecutor { ...@@ -28,13 +28,15 @@ class TheodoliteYamlExecutor {
val benchmark = val benchmark =
parser.parse(path = benchmarkPath, E = KubernetesBenchmark::class.java)!! parser.parse(path = benchmarkPath, E = KubernetesBenchmark::class.java)!!
val shutdown = Shutdown(benchmarkExecution, benchmark) // Add shutdown hook
Runtime.getRuntime().addShutdownHook(thread { shutdown.run()}) // Use thread{} with start = false, else the thread will start right away
val shutdown = thread(start = false) { Shutdown(benchmarkExecution, benchmark).run() }
Runtime.getRuntime().addShutdownHook(shutdown)
val executor = TheodoliteExecutor(benchmarkExecution, benchmark) val executor = TheodoliteExecutor(benchmarkExecution, benchmark)
executor.run() executor.run()
logger.info { "Theodolite finished" } logger.info { "Theodolite finished" }
Runtime.getRuntime().removeShutdownHook(thread { shutdown.run()}) Runtime.getRuntime().removeShutdownHook(shutdown)
exitProcess(0) exitProcess(0)
} }
} }
...@@ -7,6 +7,7 @@ import theodolite.benchmark.BenchmarkExecution ...@@ -7,6 +7,7 @@ import theodolite.benchmark.BenchmarkExecution
import theodolite.benchmark.BenchmarkExecutionList import theodolite.benchmark.BenchmarkExecutionList
import theodolite.benchmark.KubernetesBenchmark import theodolite.benchmark.KubernetesBenchmark
import theodolite.benchmark.KubernetesBenchmarkList import theodolite.benchmark.KubernetesBenchmarkList
import theodolite.k8s.K8sContextFactory
private const val DEFAULT_NAMESPACE = "default" private const val DEFAULT_NAMESPACE = "default"
......
package theodolite.execution.operator package theodolite.k8s
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
......
package theodolite.k8s
import io.fabric8.kubernetes.client.CustomResource
import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
/**
* Fabric8 handles custom resources as plain HashMaps. These need to be handled differently than normal
* Kubernetes resources. The K8sCustomResourceWrapper class provides a wrapper to deploy and delete
* custom resources in a uniform way.
*
* @property map custom resource as plain hashmap
* @constructor Create empty K8s custom resource wrapper
*/
class K8sCustomResourceWrapper(private val map : Map<String,String>) : CustomResource() {
/**
* Deploy a custom resource
*
* @param client a namespaced Kubernetes client which are used to deploy the CR object.
*/
fun deploy(client : NamespacedKubernetesClient){
val kind = this.map["kind"]
// Search the CustomResourceDefinition to which the CR Object belongs.
// This should be exactly one if the CRD is registered for Kubernetes, zero otherwise.
val crds = client.apiextensions().v1beta1().customResourceDefinitions().list()
crds.items
.filter { crd -> crd.toString().contains("kind=$kind") }
.map { crd -> CustomResourceDefinitionContext.fromCrd(crd) }
.forEach { context ->
client.customResource(context).createOrReplace(client.configuration.namespace,this.map as Map<String, Any>)
}
}
/**
* Delete a custom resource
*
* @param client a namespaced Kubernetes client which are used to delete the CR object.
*/
fun delete(client : NamespacedKubernetesClient){
val kind = this.map["kind"]
val metadata = this.map["metadata"] as HashMap<String,String>
val name = metadata["name"]
val crds = client.apiextensions().v1beta1().customResourceDefinitions().list()
crds.items
.filter { crd -> crd.toString().contains("kind=$kind") }
.map { crd -> CustomResourceDefinitionContext.fromCrd(crd) }
.forEach { context ->
client.customResource(context).delete(client.configuration.namespace,name) }
}
}
\ No newline at end of file
...@@ -19,7 +19,7 @@ class K8sManager(private val client: NamespacedKubernetesClient) { ...@@ -19,7 +19,7 @@ class K8sManager(private val client: NamespacedKubernetesClient) {
this.client.configMaps().createOrReplace(resource) this.client.configMaps().createOrReplace(resource)
is StatefulSet -> is StatefulSet ->
this.client.apps().statefulSets().createOrReplace(resource) this.client.apps().statefulSets().createOrReplace(resource)
is K8sCustomResourceWrapper -> resource.deploy(client) is ServiceMonitorWrapper -> resource.deploy(client)
else -> throw IllegalArgumentException("Unknown Kubernetes resource.") else -> throw IllegalArgumentException("Unknown Kubernetes resource.")
} }
} }
...@@ -34,7 +34,7 @@ class K8sManager(private val client: NamespacedKubernetesClient) { ...@@ -34,7 +34,7 @@ class K8sManager(private val client: NamespacedKubernetesClient) {
this.client.configMaps().delete(resource) this.client.configMaps().delete(resource)
is StatefulSet -> is StatefulSet ->
this.client.apps().statefulSets().delete(resource) this.client.apps().statefulSets().delete(resource)
is K8sCustomResourceWrapper -> resource.delete(client) is ServiceMonitorWrapper -> resource.delete(client)
else -> throw IllegalArgumentException("Unknown Kubernetes resource.") else -> throw IllegalArgumentException("Unknown Kubernetes resource.")
} }
} }
......
...@@ -26,8 +26,8 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) { ...@@ -26,8 +26,8 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) {
* @param path of the yaml file * @param path of the yaml file
* @return customResource from fabric8 * @return customResource from fabric8
*/ */
fun loadCustomResource(path: String): K8sCustomResourceWrapper { private fun loadServiceMonitor(path: String): ServiceMonitorWrapper {
return loadGenericResource(path) { x: String -> K8sCustomResourceWrapper(YamlParser().parse(path, HashMap<String, String>()::class.java)!!) } return loadGenericResource(path) { x: String -> ServiceMonitorWrapper(YamlParser().parse(path, HashMap<String, String>()::class.java)!!) }
} }
/** /**
...@@ -73,16 +73,11 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) { ...@@ -73,16 +73,11 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) {
return when (kind) { return when (kind) {
"Deployment" -> loadDeployment(path) "Deployment" -> loadDeployment(path)
"Service" -> loadService(path) "Service" -> loadService(path)
"ServiceMonitor" -> loadCustomResource(path) "ServiceMonitor" -> loadServiceMonitor(path)
"ConfigMap" -> loadConfigmap(path) "ConfigMap" -> loadConfigmap(path)
else -> { else -> {
logger.warn { "Try to load $kind from $path as Custom ressource" } logger.error { "Error during loading of unspecified resource Kind" }
try{ throw java.lang.IllegalArgumentException("error while loading resource with kind: $kind")
loadCustomResource(path)
} catch (e:Exception){
logger.error { "Error during loading of unspecified CustomResource: $e" }
throw e
}
} }
} }
} }
......
package theodolite.k8s
import io.fabric8.kubernetes.client.CustomResource
import io.fabric8.kubernetes.client.NamespacedKubernetesClient
import mu.KotlinLogging
private val logger = KotlinLogging.logger {}
class ServiceMonitorWrapper(private val serviceMonitor: Map<String, String>) : CustomResource() {
/**
* Deploy a service monitor
*
* @param client a namespaced Kubernetes client which are used to deploy the CR object.
*
* @throws java.io.IOException if the resource could not be deployed.
*/
fun deploy(client: NamespacedKubernetesClient) {
val serviceMonitorContext = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "monitoring.coreos.com",
plural = "servicemonitors"
)
client.customResource(serviceMonitorContext)
.createOrReplace(client.configuration.namespace, this.serviceMonitor as Map<String, Any>)
}
/**
* Delete a service monitor
*
* @param client a namespaced Kubernetes client which are used to delete the CR object.
*/
fun delete(client: NamespacedKubernetesClient) {
val serviceMonitorContext = K8sContextFactory().create(
api = "v1",
scope = "Namespaced",
group = "monitoring.coreos.com",
plural = "servicemonitors"
)
try {
client.customResource(serviceMonitorContext)
.delete(client.configuration.namespace, this.getServiceMonitorName())
} catch (e: Exception) {
logger.warn { "Could not delete service monitor" }
}
}
/**
* @throws NullPointerException if name or metadata is null
*/
private fun getServiceMonitorName(): String {
val smAsMap = this.serviceMonitor["metadata"]!! as Map<String, String>
return smAsMap["name"]!!
}
}
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