diff --git a/src/domains/gps-app/04_apim_gpd_debezium.tf b/src/domains/gps-app/04_apim_gpd_debezium.tf
new file mode 100644
index 0000000000..6134e34ad9
--- /dev/null
+++ b/src/domains/gps-app/04_apim_gpd_debezium.tf
@@ -0,0 +1,76 @@
+####################
+## Local variables #
+####################
+
+locals {
+ apim_gpd_debezium_api = {
+ published = false
+ subscription_required = true
+ approval_required = false
+ subscriptions_limit = 1000
+ service_url = format("https://%s/debezium-gpd", local.gps_hostname)
+ }
+}
+
+##############
+## Products ##
+##############
+
+module "apim_gpd_debezium_product" {
+ source = "./.terraform/modules/__v3__/api_management_product"
+
+ product_id = "product-gpd-debezium"
+ display_name = "GPD Debezium API pagoPA"
+ description = "Prodotto GPD Debezium API"
+
+ api_management_name = local.pagopa_apim_name
+ resource_group_name = local.pagopa_apim_rg
+
+ published = local.apim_gpd_debezium_api.published
+ subscription_required = local.apim_gpd_debezium_api.subscription_required
+ approval_required = local.apim_gpd_debezium_api.approval_required
+ subscriptions_limit = local.apim_gpd_debezium_api.subscriptions_limit
+
+ policy_xml = file("./api_product/debezium-api/_base_policy.xml")
+}
+
+##############
+## API ##
+##############
+
+resource "azurerm_api_management_api_version_set" "api_gpd_debezium_api" {
+
+ name = format("%s-api-gpd-debezium-api", var.env_short)
+ api_management_name = local.pagopa_apim_name
+ resource_group_name = local.pagopa_apim_rg
+ display_name = "GPD Debezium API"
+ versioning_scheme = "Segment"
+}
+
+
+module "apim_api_gpd_debezium_api" {
+ source = "./.terraform/modules/__v3__/api_management_api"
+
+ name = format("%s-api-gpd-debezium-api", var.env_short)
+ api_management_name = local.pagopa_apim_name
+ resource_group_name = local.pagopa_apim_rg
+ product_ids = [module.apim_gpd_debezium_product.product_id, module.apim_gpd_debezium_product.product_id]
+ subscription_required = local.apim_gpd_debezium_api.subscription_required
+ api_version = "v1"
+ version_set_id = azurerm_api_management_api_version_set.api_gpd_debezium_api.id
+ service_url = format("https://%s", module.reporting_analysis_function.default_hostname)
+
+ description = "Api GPD Debezium"
+ display_name = "GPDDebezium API pagoPA"
+ path = "gpd-debezium/api"
+ protocols = ["https"]
+
+ content_format = "openapi"
+ content_value = templatefile("./api/debezium-api/v1/_openapi.json.tpl", {
+ host = local.apim_hostname
+ })
+
+ xml_content = templatefile("./api/debezium-api/v1/_base_policy.xml", {
+ origin = format("https://%s.%s.%s", var.cname_record_name, var.apim_dns_zone_prefix, var.external_domain)
+ })
+}
diff --git a/src/domains/gps-app/05_debezium_connect.tf b/src/domains/gps-app/05_debezium_connect.tf
index 9e5fc74e33..8a78465227 100644
--- a/src/domains/gps-app/05_debezium_connect.tf
+++ b/src/domains/gps-app/05_debezium_connect.tf
@@ -91,6 +91,24 @@ locals {
max_threads = var.max_threads
})
+ healthchecker_config_yaml = templatefile("${path.module}/yaml/healthchecker-config-map.yaml", {
+ namespace = "gps" # kubernetes_namespace.namespace.metadata[0].name
+ })
+
+ debezium_health_checker_cron_yaml = templatefile("${path.module}/yaml/debezium-health-checker-cron.yaml", {
+ namespace = "gps" # kubernetes_namespace.namespace.metadata[0].name
+ })
+
+ debezium_network_policy_yaml = templatefile("${path.module}/yaml/debezium-network-policy.yaml", {
+ namespace = "gps" # kubernetes_namespace.namespace.metadata[0].name
+ })
+
+ debezium_ingress_yaml = templatefile("${path.module}/yaml/debezium-ingress.yaml", {
+ namespace = "gps" # kubernetes_namespace.namespace.metadata[0].name
+ host = "${var.location_short}${var.env_short}.gps.internal.${var.env_short}.platform.pagopa.it"
+ secret = "${var.location_short}${var.env_short}-gps-internal-${var.env_short}-platform-pagopa-it"
+ })
+
}
resource "kubectl_manifest" "debezium_role" {
@@ -178,3 +196,36 @@ resource "null_resource" "wait_postgres_connector" {
interpreter = ["/bin/bash", "-c"]
}
}
+
+resource "kubectl_manifest" "healthchecker-config-map" {
+ depends_on = [
+ helm_release.strimzi-kafka-operator
+ ]
+ force_conflicts = true
+ yaml_body = local.healthchecker_config_yaml
+}
+
+resource "kubectl_manifest" "healthchecker-cron" {
+ depends_on = [
+ helm_release.strimzi-kafka-operator, kubectl_manifest.healthchecker-config-map
+ ]
+ force_conflicts = true
+ yaml_body = local.debezium_health_checker_cron_yaml
+}
+
+resource "kubectl_manifest" "debezium-ingress" {
+ depends_on = [
+ kubectl_manifest.kafka_connect
+ ]
+ force_conflicts = true
+ yaml_body = local.debezium_ingress_yaml
+}
+
+resource "kubectl_manifest" "debezium-network-policy" {
+ depends_on = [
+ kubectl_manifest.kafka_connect
+ ]
+ force_conflicts = true
+ yaml_body = local.debezium_network_policy_yaml
+}
+
diff --git a/src/domains/gps-app/api/debezium-api/v1/_base_policy.xml b/src/domains/gps-app/api/debezium-api/v1/_base_policy.xml
new file mode 100644
index 0000000000..f9edd06caf
--- /dev/null
+++ b/src/domains/gps-app/api/debezium-api/v1/_base_policy.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/domains/gps-app/api/debezium-api/v1/_openapi.json.tpl b/src/domains/gps-app/api/debezium-api/v1/_openapi.json.tpl
new file mode 100644
index 0000000000..bd0a560a71
--- /dev/null
+++ b/src/domains/gps-app/api/debezium-api/v1/_openapi.json.tpl
@@ -0,0 +1,156 @@
+{
+ "openapi": "3.0.0",
+ "info": {
+ "title": "Debezium API - GPD",
+ "version": "1.0.0"
+ },
+ "servers": [
+ {
+ "url": "${host}"
+ }
+ ],
+ "paths": {
+ "/connectors": {
+ "get": {
+ "tags": [
+ "Get Connectors List"
+ ],
+ "summary": "getConnectors",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "Successful response",
+ "content": {
+ "application/json": {
+ }
+ }
+ },
+ "400": {
+ "description": "Error response",
+ "content": {
+ "application/json": {}
+ }
+ }
+ }
+ }
+ },
+ "/connectors/{connectorId}/status": {
+ "get": {
+ "tags": [
+ "Get Detail on Connector Status"
+ ],
+ "summary": "getConnectorStatus",
+ "parameters": [
+ {
+ "name": "connectorId",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true,
+ "example": "debezium-connector-postgres"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful response",
+ "content": {
+ "application/json": {}
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {}
+ }
+ }
+ }
+ }
+ },
+ "/connectors/{connectorId}/restart": {
+ "post": {
+ "tags": [
+ "Restart Connector"
+ ],
+ "summary": "restartConnector",
+ "parameters": [
+ {
+ "name": "connectorId",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true,
+ "example": "debezium-connector-postgres"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Successful response",
+ "content": {
+ "application/json": {}
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {}
+ }
+ }
+ }
+ }
+ },
+ "/connectors/{connectorId}/tasks/{taskId}/restart": {
+ "post": {
+ "tags": [
+ "Restart Task "
+ ],
+ "summary": "restartTask",
+ "parameters": [
+ {
+ "name": "connectorId",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true,
+ "example": "debezium-connector-postgres"
+ },
+ {
+ "name": "taskId",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true,
+ "example": "0"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Successful response",
+ "content": {
+ "application/json": {}
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {}
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "ApiKey": {
+ "type": "apiKey",
+ "description": "The API key to access this function app.",
+ "name": "Ocp-Apim-Subscription-Key",
+ "in": "header"
+ }
+ }
+ }
+}
diff --git a/src/domains/gps-app/api_product/debezium-api/_base_policy.xml b/src/domains/gps-app/api_product/debezium-api/_base_policy.xml
new file mode 100644
index 0000000000..ce1df461e7
--- /dev/null
+++ b/src/domains/gps-app/api_product/debezium-api/_base_policy.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/domains/gps-app/yaml/debezium-health-checker-cron.yaml b/src/domains/gps-app/yaml/debezium-health-checker-cron.yaml
new file mode 100644
index 0000000000..e4e6db5c9d
--- /dev/null
+++ b/src/domains/gps-app/yaml/debezium-health-checker-cron.yaml
@@ -0,0 +1,26 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: debezium-health-checker-cron
+ namespace: ${namespace}
+spec:
+ schedule: "*/5 * * * *" # Runs every 5 minutes
+ successfulJobsHistoryLimit: 0
+ failedJobsHistoryLimit: 1
+ jobTemplate:
+ spec:
+ ttlSecondsAfterFinished: 100
+ template:
+ spec:
+ containers:
+ - name: debezium-health-checker
+ image: bitnami/kubectl:latest
+ command: ["/bin/bash", "/scripts/check_kafka_connect.sh"]
+ volumeMounts:
+ - name: script-volume
+ mountPath: /scripts
+ restartPolicy: OnFailure
+ volumes:
+ - name: script-volume
+ configMap:
+ name: health-checker-script
diff --git a/src/domains/gps-app/yaml/debezium-ingress.yaml b/src/domains/gps-app/yaml/debezium-ingress.yaml
new file mode 100644
index 0000000000..2ee911e76f
--- /dev/null
+++ b/src/domains/gps-app/yaml/debezium-ingress.yaml
@@ -0,0 +1,29 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ annotations:
+ nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
+ nginx.ingress.kubernetes.io/proxy-body-size: 1m
+ nginx.ingress.kubernetes.io/rewrite-target: /$1
+ nginx.ingress.kubernetes.io/use-regex: "true"
+ labels:
+ ingress: debezium
+ name: debezium-ingress
+ namespace: ${namespace}
+spec:
+ ingressClassName: nginx
+ rules:
+ - host: ${host}
+ http:
+ paths:
+ - backend:
+ service:
+ name: debezium-connect-cluster-connect-api
+ port:
+ number: 8083
+ path: /debezium-gpd/(.*)
+ pathType: ImplementationSpecific
+ tls:
+ - hosts:
+ - ${host}
+ secretName: ${secret}
diff --git a/src/domains/gps-app/yaml/debezium-network-policy.yaml b/src/domains/gps-app/yaml/debezium-network-policy.yaml
new file mode 100644
index 0000000000..3556d0678e
--- /dev/null
+++ b/src/domains/gps-app/yaml/debezium-network-policy.yaml
@@ -0,0 +1,29 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: debezium-connect-cluster-network-policy
+ namespace: {namespace}
+spec:
+ ingress:
+ - from:
+ - podSelector:
+ matchLabels:
+ ingress: debezium
+ - podSelector:
+ matchLabels:
+ strimzi.io/cluster: debezium-connect-cluster
+ strimzi.io/kind: KafkaConnect
+ strimzi.io/name: debezium-connect-cluster-connect
+ - podSelector:
+ matchLabels:
+ strimzi.io/kind: cluster-operator
+ ports:
+ - port: 8083
+ protocol: TCP
+ podSelector:
+ matchLabels:
+ strimzi.io/cluster: debezium-connect-cluster
+ strimzi.io/kind: KafkaConnect
+ strimzi.io/name: debezium-connect-cluster-connect
+ policyTypes:
+ - Ingress
diff --git a/src/domains/gps-app/yaml/healthchecker-config-map.yaml b/src/domains/gps-app/yaml/healthchecker-config-map.yaml
new file mode 100644
index 0000000000..9add933d42
--- /dev/null
+++ b/src/domains/gps-app/yaml/healthchecker-config-map.yaml
@@ -0,0 +1,34 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: health-checker-script
+ namespace: ${namespace}
+data:
+ check_kafka_connect.sh: |
+ #!/bin/bash
+ STATUS_URL="http://debezium-connect-cluster-connect-api:8083/connectors/debezium-connector-postgres/status"
+ CONNECTOR_RESTART_URL="http://debezium-connect-cluster-connect-api:8083/connectors/debezium-connector-postgres/restart"
+ TASK_RESTART_URL="http://debezium-connect-cluster-connect-api:8083/connectors/debezium-connector-postgres/tasks"
+
+ STATUS_RESPONSE=$(curl -s -X GET "$STATUS_URL")
+
+ CONNECTOR_STATUS=$(echo "$STATUS_RESPONSE" | grep -o '"connector":{"state":"[^"]*"' | sed 's/"connector":{"state":"//;s/"//')
+
+ if [[ "$CONNECTOR_STATUS" != "RUNNING" ]]; then
+ echo "Connector is not running (state: $CONNECTOR_STATUS). Restarting..."
+ curl -s -X POST "$CONNECTOR_RESTART_URL" && echo "Connector restart command issued."
+ else
+ echo "Connector is running normally."
+ fi
+
+ TASKS=$(echo "$STATUS_RESPONSE" | grep -o '"id":[0-9]*,"state":"[^"]*"' | sed 's/"id"://;s/"state":"//;s/,/ /')
+
+ echo "$TASKS" | while read -r TASK_ID TASK_STATE; do
+ if [[ "$TASK_STATE" != "RUNNING" ]]; then
+ echo "Task $TASK_ID is not running (state: $TASK_STATE). Restarting..."
+ TASK_RESTART_API="${TASK_RESTART_URL}/${TASK_ID}/restart"
+ curl -s -X POST "$TASK_RESTART_API" && echo "Task $TASK_ID restart command issued."
+ else
+ echo "Task $TASK_ID is running normally."
+ fi
+ done