Files
flowfish/docs/REFACTORING_PLAN.md
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

399 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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**
- [x] 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`
```python
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`
```python
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`
```python
class InClusterConnection(ClusterConnection):
"""Uses cluster-manager gRPC"""
def __init__(self):
self._grpc_client = cluster_manager_client
```
Yeni dosya: `backend/services/connections/remote_token.py`
```python
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**
```python
# 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
```python
# Ö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
```python
# Ö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.py``ClusterConnectionManager` kullanacak şekilde güncelle:
```python
# Ö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**
```python
# 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ı
```python
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.