Skip to content

Commit

Permalink
feat: add webhook for status changes (#359)
Browse files Browse the repository at this point in the history
  • Loading branch information
kosmoz authored and christophenne committed Oct 11, 2023
1 parent db0d2ae commit 3f84c22
Show file tree
Hide file tree
Showing 28 changed files with 290 additions and 65 deletions.
3 changes: 3 additions & 0 deletions deploy/crd/matomos.glasskube.eu-v1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ spec:
type: object
type: object
status:
properties:
readyReplicas:
type: integer
type: object
type: object
served: true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package eu.glasskube.operator.apps.common.database

import com.fasterxml.jackson.annotation.JsonIgnore

interface HasReadyStatus {
@get:JsonIgnore
val isReady: Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import eu.glasskube.operator.apps.gitea.dependent.GiteaSSHService
import eu.glasskube.operator.apps.gitea.dependent.GiteaSecret
import eu.glasskube.operator.apps.gitea.dependent.GiteaServiceMonitor
import eu.glasskube.operator.apps.gitea.dependent.GiteaVolume
import eu.glasskube.operator.generic.BaseReconciler
import eu.glasskube.operator.infra.postgres.PostgresCluster
import eu.glasskube.operator.webhook.WebhookService
import eu.glasskube.utils.logger
import io.fabric8.kubernetes.api.model.ConfigMap
import io.fabric8.kubernetes.api.model.Service
Expand All @@ -27,7 +29,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Context
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer
import io.javaoperatorsdk.operator.api.reconciler.Reconciler
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent

Expand Down Expand Up @@ -98,24 +99,21 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
)
]
)
class GiteaReconciler : Reconciler<Gitea>, EventSourceInitializer<Gitea> {
class GiteaReconciler(webhookService: WebhookService) :
BaseReconciler<Gitea>(webhookService), EventSourceInitializer<Gitea> {

override fun reconcile(resource: Gitea, context: Context<Gitea>): UpdateControl<Gitea> {
log.info("Reconciling ${resource.metadata.name}@${resource.metadata.namespace}")
override fun processReconciliation(resource: Gitea, context: Context<Gitea>): UpdateControl<Gitea> = with(context) {
val deployment: Deployment? by secondaryResource(GiteaDeployment.Discriminator())
val redisDeployment: Deployment? by secondaryResource(GiteaRedisDeployment.Discriminator())
val postgresCluster: PostgresCluster? by secondaryResource()

return with(context) {
val deployment: Deployment? by secondaryResource(GiteaDeployment.Discriminator())
val redisDeployment: Deployment? by secondaryResource(GiteaRedisDeployment.Discriminator())
val postgresCluster: PostgresCluster? by secondaryResource()

resource.patchOrUpdateStatus(
GiteaStatus(
readyReplicas = deployment?.status?.readyReplicas ?: 0,
redisReady = redisDeployment?.status?.readyReplicas?.let { it > 0 } ?: false,
postgresReady = postgresCluster?.status?.instances?.let { it > 0 } ?: false
)
resource.patchOrUpdateStatus(
GiteaStatus(
readyReplicas = deployment?.status?.readyReplicas ?: 0,
redisReady = redisDeployment?.status?.readyReplicas?.let { it > 0 } ?: false,
postgresReady = postgresCluster?.status?.instances?.let { it > 0 } ?: false
)
}
)
}

override fun prepareEventSources(context: EventSourceContext<Gitea>) = with(context) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package eu.glasskube.operator.apps.gitea

import eu.glasskube.operator.apps.common.database.HasReadyStatus

data class GiteaStatus(
val readyReplicas: Int,
val redisReady: Boolean,
val postgresReady: Boolean
)
) : HasReadyStatus {
override val isReady get() = readyReplicas > 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import eu.glasskube.operator.apps.gitlab.dependent.GitlabService
import eu.glasskube.operator.apps.gitlab.dependent.GitlabServiceMonitor
import eu.glasskube.operator.apps.gitlab.dependent.GitlabVolume
import eu.glasskube.operator.apps.gitlab.runner.GitlabRunner
import eu.glasskube.operator.generic.BaseReconciler
import eu.glasskube.operator.infra.postgres.PostgresCluster
import eu.glasskube.operator.webhook.WebhookService
import eu.glasskube.utils.logger
import io.fabric8.kubernetes.api.model.Service
import io.fabric8.kubernetes.api.model.apps.Deployment
Expand All @@ -26,7 +28,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Context
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer
import io.javaoperatorsdk.operator.api.reconciler.Reconciler
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent

@ControllerConfiguration(
Expand Down Expand Up @@ -88,9 +89,10 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
)
]
)
class GitlabReconciler : Reconciler<Gitlab>, EventSourceInitializer<Gitlab> {
override fun reconcile(resource: Gitlab, context: Context<Gitlab>) = with(context) {
log.info("Reconciling ${resource.metadata.name}@${resource.metadata.namespace}")
class GitlabReconciler(webhookService: WebhookService) :
BaseReconciler<Gitlab>(webhookService), EventSourceInitializer<Gitlab> {

override fun processReconciliation(resource: Gitlab, context: Context<Gitlab>) = with(context) {
resource.patchOrUpdateStatus(
GitlabStatus(
getSecondaryResource<Deployment>().map { it.status?.readyReplicas ?: 0 }.orElse(0),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package eu.glasskube.operator.apps.gitlab

import eu.glasskube.operator.apps.common.database.HasReadyStatus
import eu.glasskube.operator.apps.gitlab.runner.GitlabRunnerStatus

data class GitlabStatus(
val readyReplicas: Int,
val postgresReady: Boolean,
val runners: Map<String, GitlabRunnerStatus?> = emptyMap()
)
) : HasReadyStatus {
override val isReady get() = readyReplicas > 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ import eu.glasskube.operator.apps.glitchtip.dependent.GlitchtipRedisService
import eu.glasskube.operator.apps.glitchtip.dependent.GlitchtipSecret
import eu.glasskube.operator.apps.glitchtip.dependent.GlitchtipVolume
import eu.glasskube.operator.apps.glitchtip.dependent.GlitchtipWorkerDeployment
import eu.glasskube.operator.generic.BaseReconciler
import eu.glasskube.operator.generic.condition.isReady
import eu.glasskube.operator.infra.postgres.PostgresCluster
import eu.glasskube.operator.infra.postgres.isReady
import eu.glasskube.operator.webhook.WebhookService
import eu.glasskube.utils.logger
import io.fabric8.kubernetes.api.model.Service
import io.fabric8.kubernetes.api.model.apps.Deployment
import io.javaoperatorsdk.operator.api.reconciler.Context
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer
import io.javaoperatorsdk.operator.api.reconciler.Reconciler
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
import kotlin.jvm.optionals.getOrDefault

Expand Down Expand Up @@ -88,9 +89,10 @@ import kotlin.jvm.optionals.getOrDefault
)
]
)
class GlitchtipReconciler : Reconciler<Glitchtip>, EventSourceInitializer<Glitchtip> {
override fun reconcile(resource: Glitchtip, context: Context<Glitchtip>) = with(context) {
log.info("Reconciling ${resource.metadata.name}@${resource.metadata.namespace}")
class GlitchtipReconciler(webhookService: WebhookService) :
BaseReconciler<Glitchtip>(webhookService), EventSourceInitializer<Glitchtip> {

override fun processReconciliation(resource: Glitchtip, context: Context<Glitchtip>) = with(context) {
resource.patchOrUpdateStatus(
GlitchtipStatus(
readyReplicas = getSecondaryResource(GlitchtipDeployment.Discriminator())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package eu.glasskube.operator.apps.glitchtip

import eu.glasskube.operator.apps.common.database.HasReadyStatus

data class GlitchtipStatus(
val readyReplicas: Int,
val workerReadyReplicas: Int,
val redisReady: Boolean,
val postgresReady: Boolean
)
) : HasReadyStatus {
override val isReady get() = readyReplicas > 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ import eu.glasskube.operator.apps.keycloak.dependent.KeycloakPostgresBackup
import eu.glasskube.operator.apps.keycloak.dependent.KeycloakPostgresBackupBucket
import eu.glasskube.operator.apps.keycloak.dependent.KeycloakPostgresCluster
import eu.glasskube.operator.apps.keycloak.dependent.KeycloakService
import eu.glasskube.operator.generic.BaseReconciler
import eu.glasskube.operator.infra.postgres.PostgresCluster
import eu.glasskube.operator.infra.postgres.isReady
import eu.glasskube.operator.webhook.WebhookService
import io.fabric8.kubernetes.api.model.Service
import io.fabric8.kubernetes.api.model.apps.Deployment
import io.javaoperatorsdk.operator.api.reconciler.Context
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer
import io.javaoperatorsdk.operator.api.reconciler.Reconciler
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
import kotlin.jvm.optionals.getOrDefault

Expand Down Expand Up @@ -59,8 +59,10 @@ import kotlin.jvm.optionals.getOrDefault
Dependent(type = KeycloakIngress::class, name = "KeycloakIngress")
]
)
class KeycloakReconciler : Reconciler<Keycloak>, EventSourceInitializer<Keycloak> {
override fun reconcile(resource: Keycloak, context: Context<Keycloak>): UpdateControl<Keycloak> = with(context) {
class KeycloakReconciler(webhookService: WebhookService) :
BaseReconciler<Keycloak>(webhookService), EventSourceInitializer<Keycloak> {

override fun processReconciliation(resource: Keycloak, context: Context<Keycloak>) = with(context) {
resource.patchOrUpdateStatus(
KeycloakStatus(
getSecondaryResource<Deployment>().map { it.status?.readyReplicas ?: 0 }.getOrDefault(0),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package eu.glasskube.operator.apps.keycloak

import eu.glasskube.operator.apps.common.database.HasReadyStatus

data class KeycloakStatus(
val readyInstances: Int,
val postgresReady: Boolean
)
) : HasReadyStatus {
override val isReady get() = readyInstances > 0
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package eu.glasskube.operator.apps.matomo

import eu.glasskube.operator.apps.common.database.HasDatabaseSpec
import eu.glasskube.operator.apps.common.database.HasReadyStatus
import eu.glasskube.operator.apps.common.database.ResourceWithDatabaseSpec
import eu.glasskube.operator.apps.common.database.mariadb.MariaDbDatabaseSpec
import eu.glasskube.utils.resourceLabels
Expand All @@ -26,9 +27,8 @@ data class MatomoSpec(
override val database: MariaDbDatabaseSpec = MariaDbDatabaseSpec()
) : HasDatabaseSpec<MariaDbDatabaseSpec>

class MatomoStatus {
override fun equals(other: Any?) = this === other || javaClass == other?.javaClass
override fun hashCode() = javaClass.hashCode()
data class MatomoStatus(val readyReplicas: Int) : HasReadyStatus {
override val isReady get() = readyReplicas > 0
}

@Group("glasskube.eu")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eu.glasskube.operator.apps.matomo
import eu.glasskube.kubernetes.client.patchOrUpdateStatus
import eu.glasskube.kubernetes.client.resources
import eu.glasskube.operator.api.reconciler.HasRegistrationCondition
import eu.glasskube.operator.api.reconciler.getSecondaryResource
import eu.glasskube.operator.api.reconciler.informerEventSource
import eu.glasskube.operator.apps.matomo.Matomo.Companion.APP_NAME
import eu.glasskube.operator.apps.matomo.dependent.MatomoConfigMap
Expand All @@ -14,18 +15,20 @@ import eu.glasskube.operator.apps.matomo.dependent.MatomoIngress
import eu.glasskube.operator.apps.matomo.dependent.MatomoMariaDB
import eu.glasskube.operator.apps.matomo.dependent.MatomoService
import eu.glasskube.operator.apps.matomo.dependent.MatomoVolume
import eu.glasskube.operator.generic.BaseReconciler
import eu.glasskube.operator.webhook.WebhookService
import eu.glasskube.utils.logger
import io.fabric8.kubernetes.api.model.PersistentVolumeClaim
import io.fabric8.kubernetes.api.model.Secret
import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition
import io.fabric8.kubernetes.api.model.apps.Deployment
import io.fabric8.kubernetes.client.KubernetesClient
import io.javaoperatorsdk.operator.api.reconciler.Context
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer
import io.javaoperatorsdk.operator.api.reconciler.Reconciler
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
import kotlin.jvm.optionals.getOrNull

@ControllerConfiguration(
dependents = [
Expand Down Expand Up @@ -54,8 +57,8 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
Dependent(type = MatomoCronJob::class, name = "MatomoCronJob", dependsOn = ["MatomoDeployment"])
]
)
class MatomoReconciler(private val kubernetesClient: KubernetesClient) :
Reconciler<Matomo>, EventSourceInitializer<Matomo>, HasRegistrationCondition {
class MatomoReconciler(private val kubernetesClient: KubernetesClient, webhookService: WebhookService) :
BaseReconciler<Matomo>(webhookService), EventSourceInitializer<Matomo>, HasRegistrationCondition {

override val isRegistrationEnabled
get() = kubernetesClient.resources<CustomResourceDefinition>()
Expand All @@ -65,15 +68,19 @@ class MatomoReconciler(private val kubernetesClient: KubernetesClient) :
override val registrationConditionHint =
"CRDs provided by the MariaDB Operator must be present on the cluster."

override fun reconcile(resource: Matomo, context: Context<Matomo>): UpdateControl<Matomo> {
context.getSecondaryResources(PersistentVolumeClaim::class.java)
override fun processReconciliation(resource: Matomo, context: Context<Matomo>) = with(context) {
getSecondaryResources(PersistentVolumeClaim::class.java)
.filter { it.metadata.name.endsWith("-misc") }
.forEach {
log.info("Deleting old persisted volume claim ${it.metadata.name}")
kubernetesClient.persistentVolumeClaims().resource(it).delete()
}

return resource.patchOrUpdateStatus(MatomoStatus())
resource.patchOrUpdateStatus(
MatomoStatus(
readyReplicas = getSecondaryResource<Deployment>().getOrNull()?.status?.readyReplicas ?: 0
)
)
}

override fun prepareEventSources(context: EventSourceContext<Matomo>) = with(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import eu.glasskube.operator.apps.metabase.dependent.MetabasePostgresBackup
import eu.glasskube.operator.apps.metabase.dependent.MetabasePostgresCluster
import eu.glasskube.operator.apps.metabase.dependent.MetabaseSecret
import eu.glasskube.operator.apps.metabase.dependent.MetabaseServiceMonitor
import eu.glasskube.operator.generic.BaseReconciler
import eu.glasskube.operator.infra.postgres.PostgresCluster
import eu.glasskube.operator.webhook.WebhookService
import eu.glasskube.utils.logger
import io.fabric8.kubernetes.api.model.apps.Deployment
import io.javaoperatorsdk.operator.api.reconciler.Context
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration
import io.javaoperatorsdk.operator.api.reconciler.Reconciler
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent

@ControllerConfiguration(
Expand Down Expand Up @@ -64,10 +65,9 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
)
]
)
class MetabaseReconciler : Reconciler<Metabase> {
class MetabaseReconciler(webhookService: WebhookService) : BaseReconciler<Metabase>(webhookService) {

override fun reconcile(resource: Metabase, context: Context<Metabase>) = with(context) {
log.info("Reconciling ${resource.metadata.name}@${resource.metadata.namespace}")
override fun processReconciliation(resource: Metabase, context: Context<Metabase>) = with(context) {
resource.patchOrUpdateStatus(
MetabaseStatus(
getSecondaryResource<Deployment>().map { it.status?.readyReplicas ?: 0 }.orElse(0),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package eu.glasskube.operator.apps.metabase

import eu.glasskube.operator.apps.common.database.HasReadyStatus

data class MetabaseStatus(
val readyReplicas: Int,
val postgresReady: Boolean
)
) : HasReadyStatus {
override val isReady get() = readyReplicas > 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ import eu.glasskube.operator.apps.nextcloud.dependent.NextcloudRedisDeployment
import eu.glasskube.operator.apps.nextcloud.dependent.NextcloudRedisService
import eu.glasskube.operator.apps.nextcloud.dependent.NextcloudService
import eu.glasskube.operator.apps.nextcloud.dependent.NextcloudVolume
import eu.glasskube.operator.generic.BaseReconciler
import eu.glasskube.operator.generic.condition.isReady
import eu.glasskube.operator.infra.postgres.PostgresCluster
import eu.glasskube.operator.infra.postgres.isReady
import eu.glasskube.operator.webhook.WebhookService
import eu.glasskube.utils.logger
import io.fabric8.kubernetes.api.model.Service
import io.fabric8.kubernetes.api.model.apps.Deployment
import io.javaoperatorsdk.operator.api.reconciler.Context
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer
import io.javaoperatorsdk.operator.api.reconciler.Reconciler
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent
import kotlin.jvm.optionals.getOrDefault

Expand Down Expand Up @@ -88,9 +89,10 @@ import kotlin.jvm.optionals.getOrDefault
)
]
)
class NextcloudReconciler : Reconciler<Nextcloud>, EventSourceInitializer<Nextcloud> {
override fun reconcile(resource: Nextcloud, context: Context<Nextcloud>) = with(context) {
log.info("Reconciling ${resource.metadata.name}@${resource.metadata.namespace}")
class NextcloudReconciler(webhookService: WebhookService) :
BaseReconciler<Nextcloud>(webhookService), EventSourceInitializer<Nextcloud> {

override fun processReconciliation(resource: Nextcloud, context: Context<Nextcloud>) = with(context) {
resource.patchOrUpdateStatus(
NextcloudStatus(
readyReplicas = getSecondaryResource(NextcloudDeployment.Discriminator())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package eu.glasskube.operator.apps.nextcloud

import eu.glasskube.operator.apps.common.database.HasReadyStatus

data class NextcloudStatus(
val readyReplicas: Int,
val redisReady: Boolean,
val postgresReady: Boolean,
val officeReady: Boolean
)
) : HasReadyStatus {
override val isReady get() = readyReplicas > 0
}
Loading

0 comments on commit 3f84c22

Please sign in to comment.