# =====================================================================
# PrometheusRule: alert infrastrutturali + CNPG
# Applica con: kubectl apply -f 03-alert-rules.yaml
# =====================================================================

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: infra-alerts
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  groups:
    - name: node-health
      rules:
        - alert: NodeDown
          expr: up{job="node-exporter"} == 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Nodo {{ $labels.instance }} irraggiungibile"
            description: "node-exporter non risponde da 5 minuti su {{ $labels.instance }}."

        - alert: NodeHighCPU
          expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "CPU alta su {{ $labels.instance }}"
            description: "Uso CPU sopra 85% da 10 minuti."

        - alert: NodeHighMemory
          expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Memoria alta su {{ $labels.instance }}"
            description: "Uso memoria sopra 90% da 10 minuti."

        - alert: NodeDiskSpaceLow
          expr: (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) * 100 < 15
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Spazio disco basso su {{ $labels.instance }} ({{ $labels.mountpoint }})"
            description: "Meno del 15% di spazio libero da 10 minuti."

        - alert: NodeDiskSpaceCritical
          expr: (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) * 100 < 5
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Spazio disco CRITICO su {{ $labels.instance }} ({{ $labels.mountpoint }})"
            description: "Meno del 5% di spazio libero da 5 minuti."

    - name: kubernetes-health
      rules:
        - alert: KubePodCrashLooping
          expr: increase(kube_pod_container_status_restarts_total[15m]) > 3
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} in crash loop"
            description: "Più di 3 restart negli ultimi 15 minuti."

        - alert: KubePodNotReady
          expr: sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown"}) > 0
          for: 15m
          labels:
            severity: warning
          annotations:
            summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} non Ready da 15 minuti"

        - alert: KubeDeploymentReplicasMismatch
          expr: kube_deployment_spec_replicas != kube_deployment_status_replicas_available
          for: 15m
          labels:
            severity: warning
          annotations:
            summary: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} con repliche non allineate"

        - alert: KubePersistentVolumeFillingUp
          expr: (kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes) * 100 < 10
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "PVC {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} quasi pieno"
            description: "Meno del 10% di spazio libero sul volume."

        - alert: EtcdInsufficientMembers
          expr: sum(up{job="kube-etcd"} == 1) < ((count(up{job="kube-etcd"}) + 1) / 2)
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Quorum etcd a rischio"
            description: "Meno della maggioranza dei membri etcd è raggiungibile."

    - name: tls-certificates
      rules:
        # Richiede blackbox_exporter con probe HTTPS configurato sui tuoi
        # endpoint esterni; vedi nota nel file README.
        - alert: TLSCertExpiringSoon
          expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 15
          for: 1h
          labels:
            severity: warning
          annotations:
            summary: "Certificato TLS per {{ $labels.instance }} in scadenza"
            description: "Meno di 15 giorni alla scadenza del certificato."

        - alert: TLSCertExpired
          expr: probe_ssl_earliest_cert_expiry - time() < 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Certificato TLS per {{ $labels.instance }} SCADUTO"

---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: cnpg-alerts
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  groups:
    - name: cnpg-health
      rules:
        - alert: CNPGClusterNotHealthy
          expr: cnpg_collector_up == 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Cluster CNPG {{ $labels.namespace }}/{{ $labels.pod }} non raggiungibile"
            description: "L'exporter CNPG non risponde da 5 minuti."

        - alert: CNPGInstanceInUnexpectedRecovery
          expr: cnpg_pg_replication_in_recovery == 1 and on(pod) cnpg_pg_replication_is_wal_receiver_up == 0
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "Istanza {{ $labels.pod }} in recovery inatteso"
            description: "Verifica se il ruolo primary/standby è quello atteso."

        - alert: CNPGReplicationLagHigh
          expr: cnpg_pg_replication_lag > 300
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "Replication lag alto su {{ $labels.pod }}"
            description: "Lag di replica superiore a 300 secondi."

        - alert: CNPGWALArchivingFailing
          expr: increase(cnpg_pg_stat_archiver_failed_count[15m]) > 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Archiviazione WAL fallita su {{ $labels.pod }}"
            description: "Almeno un fallimento di archiviazione WAL negli ultimi 15 minuti — rischio per i backup e il point-in-time recovery."

        - alert: CNPGBackupFailed
          expr: cnpg_collector_last_failed_backup_timestamp > cnpg_collector_last_available_backup_timestamp
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Ultimo backup fallito per {{ $labels.namespace }}/{{ $labels.pod }}"

        - alert: CNPGNoRecentBackup
          expr: (time() - cnpg_collector_last_available_backup_timestamp) > 86400
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Nessun backup riuscito nelle ultime 24h per {{ $labels.namespace }}/{{ $labels.pod }}"

        - alert: CNPGConnectionsNearLimit
          expr: (cnpg_backends_total / cnpg_pg_settings_setting{name="max_connections"}) * 100 > 85
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Connessioni Postgres vicine al limite su {{ $labels.pod }}"
            description: "Oltre l'85% di max_connections in uso."

    # Nota: i nomi esatti delle metriche cnpg_* possono variare leggermente
    # tra versioni dell'operatore CNPG. Verifica sempre su
    # http://localhost:9090/graph con `{__name__=~"cnpg_.+"}` dopo il
    # port-forward a Prometheus, e allinea le espressioni se necessario:
    #   kubectl port-forward -n monitoring svc/kube-prometheus-stack-prometheus 9090
