Files
flowfish/docs/REFACTORING_PLAN.md
T
taylanbakircioglu d7ca50b387 feat: Flowfish - eBPF-powered multi-cluster Kubernetes observability platform
Multi-cluster dependency mapping, real-time network monitoring,
impact analysis, and CI/CD integration capabilities.

Made-with: Cursor
2026-03-29 21:43:20 +03:00

17 KiB
Raw Permalink Blame History

Cluster Connection Manager - Refactoring Plan

TAMAMLANDI - 23 Aralık 2025

Bu refactoring planı başarıyla tamamlandı. Tüm fazlar uygulandı ve mevcut fonksiyonellik korunarak, merkezi bir ClusterConnectionManager mimarisine geçildi.

Executive Summary

Bu plan, mevcut dağınık cluster bağlantı yönetimini merkezi bir ClusterConnectionManager servisine taşımayı amaçlar. Mevcut fonksiyonellik korunarak, aşamalı bir geçiş yapılacaktır.


1. ETKİ ANALİZİ

1.1 Mevcut Servisler ve Sorumlulukları

Servis Dosya Sorumluluk Kullanım
cluster_info_service services/cluster_info_service.py Remote K8s API erişimi (token/kubeconfig) clusters.py, cluster_cache_service.py
cluster_manager_client grpc_clients/cluster_manager_client.py In-cluster gRPC (cluster-manager pod) clusters.py, cluster_cache_service.py, namespaces.py
cluster_cache_service services/cluster_cache_service.py Redis cache layer namespaces.py, clusters.py
kubernetes_service services/kubernetes_service.py Cluster CRUD, connection test clusters.py

1.2 Fonksiyon Kullanım Haritası

┌─────────────────────────────────────────────────────────────────────────────┐
│                              ROUTER LAYER                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  clusters.py                                                                 │
│  ├── sync_cluster_data()                                                    │
│  │   ├── cluster_manager_client.get_cluster_info() [in-cluster]            │
│  │   ├── cluster_info_service.get_cluster_info() [remote]                  │
│  │   ├── cluster_manager_client.check_gadget_health() [in-cluster]         │
│  │   └── cluster_info_service.check_gadget_health() [remote]               │
│  │                                                                          │
│  ├── get_cluster() → [line 1509-1540]                                       │
│  │   ├── cluster_manager_client.get_cluster_info() [in-cluster]            │
│  │   ├── cluster_info_service.get_cluster_info() [remote]                  │
│  │   └── cluster_manager_client.check_gadget_health()                       │
│  │                                                                          │
│  └── test_cluster_connection()                                              │
│      ├── cluster_manager_client.get_cluster_info() [in-cluster]            │
│      ├── cluster_info_service.get_cluster_info() [token/kubeconfig]        │
│      ├── cluster_manager_client.check_gadget_health() [in-cluster]         │
│      └── Direct HTTP to gadget_endpoint [remote] *YENİ EKLENDİ*            │
│                                                                              │
│  namespaces.py                                                               │
│  ├── get_namespaces() → cluster_cache_service.get_namespaces()             │
│  ├── get_deployments() → cluster_cache_service.get_deployments()           │
│  ├── get_pods() → cluster_cache_service.get_pods()                          │
│  ├── get_labels() → cluster_cache_service.get_labels()                      │
│  └── get_services() → cluster_manager_client.list_services() [direct]      │
│                                                                              │
│  workloads.py                                                                │
│  └── get_workloads() → Database only (no K8s API)                           │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                            SERVICE LAYER                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  cluster_cache_service.py                                                    │
│  ├── get_cluster_info()                                                      │
│  │   ├── cluster_info_service.get_cluster_info() [remote]                  │
│  │   └── cluster_manager_client.get_cluster_info() [in-cluster]            │
│  │                                                                          │
│  ├── get_namespaces()                                                        │
│  │   ├── cluster_info_service.get_namespaces() [remote]                    │
│  │   └── cluster_manager_client.list_namespaces() [in-cluster]             │
│  │                                                                          │
│  ├── get_deployments()                                                       │
│  │   ├── cluster_info_service.get_deployments() [remote]                   │
│  │   └── cluster_manager_client.list_deployments() [in-cluster]            │
│  │                                                                          │
│  ├── get_pods()                                                              │
│  │   └── cluster_manager_client.list_pods() [both - TODO: add remote]      │
│  │                                                                          │
│  ├── get_labels()                                                            │
│  │   ├── cluster_info_service.get_labels() [remote]                        │
│  │   └── cluster_manager_client.get_labels() [in-cluster]                  │
│  │                                                                          │
│  └── get_gadget_health()                                                     │
│      └── cluster_manager_client.check_gadget_health() [in-cluster only!]   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

1.3 Kritik Bağımlılıklar

Bağımlılık Risk Etki
cluster_manager_client gRPC proto YÜKSEK Proto değişirse tüm in-cluster çağrılar bozulur
cluster_info_service K8s client ORTA Token/kubeconfig geçersizse remote cluster erişimi yok
Redis cache DÜŞÜK Cache yoksa sadece performans düşer
PostgreSQL credentials YÜKSEK Şifreli token/cert okunamazsa remote erişim yok

1.4 Eksiklikler (Mevcut Sistem)

  1. cluster_cache_service.get_pods() - Remote cluster için cluster_info_service.get_pods() YOK
  2. cluster_cache_service.get_gadget_health() - Remote cluster desteği YOK
  3. namespaces.py/get_services() - Remote cluster desteği YOK
  4. Connection pooling YOK
  5. Credential refresh/rotation YOK
  6. Circuit breaker YOK

2. REFACTORING PLANI

Faz 0: Hazırlık (Mevcut Kodu Stabilize Et)

Süre: 30 dakika

  • Mevcut test connection düzeltmesi (gadget HTTP)
  • Eksik get_pods() metodunu cluster_info_service'e ekle
  • Eksik get_services() metodunu cluster_info_service'e ekle
  • Remote gadget health check metodunu cluster_info_service'e ekle

Faz 1: ClusterConnectionManager Skeleton

Süre: 1 saat

Yeni dosya: backend/services/cluster_connection_manager.py

class ClusterConnectionManager:
    """
    Unified cluster connection manager.
    Single entry point for all cluster operations.
    """
    
    # Connection Management
    async def get_connection(cluster_id: int) -> ClusterConnection
    async def test_connection(config: ConnectionConfig) -> TestResult
    async def close_connection(cluster_id: int)
    async def close_all()
    
    # Cluster Info
    async def get_cluster_info(cluster_id: int) -> ClusterInfo
    async def get_namespaces(cluster_id: int) -> List[Namespace]
    async def get_deployments(cluster_id: int, namespace: str) -> List[Deployment]
    async def get_pods(cluster_id: int, namespace: str) -> List[Pod]
    async def get_services(cluster_id: int, namespace: str) -> List[Service]
    async def get_labels(cluster_id: int, namespace: str) -> List[Label]
    
    # Gadget
    async def check_gadget_health(cluster_id: int) -> GadgetHealth
    
    # Health Monitoring
    async def health_check_all() -> Dict[int, HealthStatus]

Faz 2: ClusterConnection Abstraction

Süre: 1.5 saat

Yeni dosya: backend/services/connections/base.py

class ClusterConnection(ABC):
    """Abstract base for cluster connections"""
    
    @abstractmethod
    async def get_k8s_client(self) -> ApiClient
    
    @abstractmethod
    async def get_cluster_info(self) -> ClusterInfo
    
    @abstractmethod
    async def check_gadget_health(self) -> GadgetHealth

Yeni dosya: backend/services/connections/in_cluster.py

class InClusterConnection(ClusterConnection):
    """Uses cluster-manager gRPC"""
    
    def __init__(self):
        self._grpc_client = cluster_manager_client

Yeni dosya: backend/services/connections/remote_token.py

class RemoteTokenConnection(ClusterConnection):
    """Direct K8s API with token auth"""
    
    def __init__(self, api_url, token, ca_cert, skip_tls):
        self._config = self._create_config()

Faz 3: Mevcut Servisleri Adapter Pattern ile Wrap Et

Süre: 1 saat

# cluster_connection_manager.py

class ClusterConnectionManager:
    def __init__(self):
        self._connections: Dict[int, ClusterConnection] = {}
        
        # Wrap existing services (backward compatibility)
        self._cluster_info_service = cluster_info_service
        self._cluster_manager_client = cluster_manager_client

ÖNEMLİ: Bu aşamada mevcut servisler DEĞİŞTİRİLMEZ, sadece wrap edilir.

Faz 4: Router Migration (Aşamalı)

Süre: 2 saat

4.1 clusters.py Güncellemesi

# ÖNCE (mevcut)
cluster_info = await cluster_info_service.get_cluster_info(...)

# SONRA (yeni)
cluster_info = await cluster_connection_manager.get_cluster_info(cluster_id)

4.2 namespaces.py Güncellemesi

# ÖNCE (mevcut)
services = await cluster_manager_client.list_services(...)

# SONRA (yeni)
services = await cluster_connection_manager.get_services(cluster_id, namespace)

Faz 5: Cache Service Integration

Süre: 1 saat

cluster_cache_service.pyClusterConnectionManager kullanacak şekilde güncelle:

# ÖNCE
if self._is_remote_cluster(connection_info):
    data = await cluster_info_service.get_cluster_info(...)
else:
    data = await cluster_manager_client.get_cluster_info(...)

# SONRA
data = await cluster_connection_manager.get_cluster_info(cluster_id)

Faz 6: Health Monitoring (Background Task)

Süre: 1 saat

# backend/services/health/cluster_health_monitor.py

class ClusterHealthMonitor:
    """Background task for periodic health checks"""
    
    async def start(self):
        while True:
            await self._check_all_clusters()
            await asyncio.sleep(HEALTH_CHECK_INTERVAL)
    
    async def _check_all_clusters(self):
        clusters = await self._get_active_clusters()
        for cluster in clusters:
            try:
                health = await cluster_connection_manager.check_gadget_health(cluster.id)
                await self._update_health_status(cluster.id, health)
            except Exception as e:
                logger.error("Health check failed", cluster_id=cluster.id, error=str(e))

Faz 7: Cleanup ve Deprecation

Süre: 30 dakika

  1. Eski servisleri deprecated olarak işaretle
  2. Import warning'leri ekle
  3. Dokümantasyon güncelle

3. DOSYA YAPISI (SONUÇ)

backend/
├── services/
│   ├── cluster_connection_manager.py    # YENİ - Merkezi Manager
│   ├── connections/                      # YENİ - Connection implementations
│   │   ├── __init__.py
│   │   ├── base.py                       # Abstract base class
│   │   ├── in_cluster.py                 # InClusterConnection
│   │   ├── remote_token.py               # RemoteTokenConnection
│   │   └── remote_kubeconfig.py          # RemoteKubeconfigConnection
│   ├── health/                           # YENİ - Health monitoring
│   │   ├── __init__.py
│   │   └── cluster_health_monitor.py
│   │
│   ├── cluster_info_service.py           # MEVCUT - Deprecate sonra
│   ├── cluster_cache_service.py          # MEVCUT - Güncelle
│   ├── kubernetes_service.py             # MEVCUT - Koru
│   └── event_service.py                  # MEVCUT - Değişmez
│
├── grpc_clients/
│   └── cluster_manager_client.py         # MEVCUT - Internal kullanım
│
└── routers/
    ├── clusters.py                       # Güncelle
    └── namespaces.py                     # Güncelle

4. MİGRASYON TABLOSU

Mevcut Çağrı Yeni Çağrı Dosya
cluster_info_service.get_cluster_info() ccm.get_cluster_info() clusters.py
cluster_manager_client.get_cluster_info() ccm.get_cluster_info() clusters.py
cluster_info_service.check_gadget_health() ccm.check_gadget_health() clusters.py
cluster_manager_client.check_gadget_health() ccm.check_gadget_health() clusters.py, cache
cluster_info_service.get_namespaces() ccm.get_namespaces() cache
cluster_manager_client.list_namespaces() ccm.get_namespaces() cache
cluster_info_service.get_deployments() ccm.get_deployments() cache
cluster_manager_client.list_deployments() ccm.get_deployments() cache
cluster_manager_client.list_pods() ccm.get_pods() cache
cluster_info_service.get_labels() ccm.get_labels() cache
cluster_manager_client.get_labels() ccm.get_labels() cache
cluster_manager_client.list_services() ccm.get_services() namespaces.py

5. RİSK YÖNETİMİ

5.1 Rollback Stratejisi

Her faz için rollback:

  • Faz 1-3: Yeni dosyaları sil, import'ları kaldır
  • Faz 4-5: Git revert ile eski router/service koduna dön
  • Faz 6: Background task'ı devre dışı bırak

5.2 Test Stratejisi

Her faz sonrası test:

  1. In-cluster connection çalışıyor mu?
  2. Remote token connection çalışıyor mu?
  3. Cache çalışıyor mu?
  4. Gadget health check çalışıyor mu?
  5. UI cluster listesi yükleniyor mu?
  6. UI test connection çalışıyor mu?

5.3 Fallback Mekanizması

class ClusterConnectionManager:
    async def get_cluster_info(self, cluster_id: int):
        try:
            # Yeni yöntem
            connection = await self.get_connection(cluster_id)
            return await connection.get_cluster_info()
        except Exception as e:
            # Fallback: Eski yöntem
            logger.warning("Falling back to legacy service", error=str(e))
            return await self._legacy_get_cluster_info(cluster_id)

6. UYGULAMA TAKVİMİ

Faz Görev Süre Kümülatif
0 Hazırlık - Eksik metodları ekle 30 dk 30 dk
1 ClusterConnectionManager skeleton 1 saat 1.5 saat
2 Connection abstractions 1.5 saat 3 saat
3 Adapter pattern wrap 1 saat 4 saat
4 Router migration 2 saat 6 saat
5 Cache service integration 1 saat 7 saat
6 Health monitoring 1 saat 8 saat
7 Cleanup & docs 30 dk 8.5 saat

TOPLAM: ~8.5 saat (yaklaşık 1-2 iş günü)


7. BAŞLANGIÇ NOKTASI

Faz 0'dan başlıyoruz:

  1. cluster_info_service'e eksik metodları ekle:

    • get_pods()
    • get_services()
    • check_gadget_health_remote() (HTTP-based)
  2. Mevcut test connection fix'ini commit'le

Başlamak için onayınızı bekliyorum.