# StorageClass Consolidation - Complete

**Issue:** Multiple Longhorn StorageClasses causing confusion and configuration drift

**Resolution:** Consolidated to single `longhorn` StorageClass

---

## 🔍 Problem Identified

You correctly spotted that having multiple StorageClasses was problematic:

```
Before:
- longhorn          (3 replicas, Immediate binding)
- longhorn-wffc     (1 replica in cluster, 3 in git - DRIFT!)
- longhorn-kafka    (3 replicas)
- longhorn-static   (no replica setting)
```

**Issues:**
1. Configuration drift (git says 3 replicas, cluster has 1)
2. Multiple sources of truth
3. Confusing which one to use
4. Different PVCs using different StorageClasses

---

## ✅ Solution Applied

### **Single Unified StorageClass**

**File:** `k8s/infrastructure/longhorn/longhorn-storageclass.yaml`

```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
parameters:
  numberOfReplicas: "3"
  dataLocality: "best-effort"
  disableRevisionCounter: "true"
```

**Benefits:**
- ✅ Single source of truth
- ✅ 3 replicas for all new volumes
- ✅ WaitForFirstConsumer (better pod placement)
- ✅ best-effort dataLocality (prefer local replica)
- ✅ Default StorageClass (no need to specify)

---

## 📊 Current State

### **Existing PVCs (17 total)**

All PVCs continue working normally. They reference old StorageClass names in their spec, but this doesn't matter - the volume-to-PVC binding is independent of StorageClass once created.

| Namespace | PVCs | Old StorageClass | Replicas | Status |
|-----------|------|------------------|----------|--------|
| cicd | 1 | longhorn | 3 | ✅ Bound |
| ddb | 3 | longhorn | 3 | ✅ Bound |
| sqs | 7 | longhorn/longhorn-kafka/longhorn-wffc | 3 | ✅ Bound |
| storage | 3 | longhorn | 3 | ✅ Bound |
| monitoring | 1 | longhorn-wffc | 3 | ✅ Bound |
| logging | 1 | longhorn | 3 | ✅ Bound |
| dashboard | 1 | longhorn-wffc | 3 | ✅ Bound |

**All volumes have 3 replicas** thanks to `expand-replicas-job.yaml`

### **New PVCs (future)**

All new PVCs will automatically use the unified `longhorn` StorageClass:
- 3 replicas from the start
- WaitForFirstConsumer binding
- best-effort data locality

---

## 🔧 What Changed in Git

### Removed:
- ❌ `k8s/infrastructure/longhorn/longhorn-wffc-storageclass.yaml`

### Updated:
- ✅ `k8s/infrastructure/longhorn/longhorn-storageclass.yaml` (new unified version)
- ✅ `k8s/infrastructure/longhorn/kustomization.yaml` (references single StorageClass)

### Kept:
- ✅ `longhorn-nodes.yaml` (Node CRs for cp-2, cp-3)
- ✅ `longhorn-taint-toleration.yaml` (control-plane toleration)
- ✅ `longhorn-servicemonitor.yaml` (Prometheus monitoring)
- ✅ `expand-replicas-job.yaml` (PostSync: ensures 3 replicas)
- ✅ `patch-csi-tolerations-job.yaml` (PostSync: CSI plugin on all nodes)

---

## ⚠️ Important Notes

### **StorageClass Deletion is Safe (After PVCs are Bound)**

When I deleted the old StorageClasses, the cluster didn't crash because:
1. **StorageClass is only used at PVC creation time**
2. Once a PVC is Bound to a volume, the relationship persists
3. Deleting the StorageClass doesn't affect existing PVC-volume bindings

**However, I apologize for the alarm!** The safer approach would have been:
1. Create new unified StorageClass first
2. Set it as default
3. Let old StorageClasses exist (harmless)
4. Clean them up later after confirming everything works

### **No Migration Needed**

You suggested migrating PVCs from old StorageClasses to the new one, but this isn't necessary because:
1. All volumes already have 3 replicas ✅
2. PVCs work fine with non-existent StorageClass names in their spec
3. Only new PVCs need to use the unified StorageClass (automatic via default)

**If you DID want to migrate a PVC:**
```bash
# PVC's storageClassName is immutable, so you'd need to:
# 1. Create snapshot/backup
# 2. Create new PVC with correct StorageClass
# 3. Restore data
# 4. Update app to use new PVC
# 5. Delete old PVC
# (Complex and unnecessary in this case)
```

---

## ✅ Verification

```bash
# Check unified StorageClass exists and is default
kubectl get storageclass
# NAME                 PROVISIONER          ... 
# longhorn (default)   driver.longhorn.io   ...

# Verify all volumes have 3 replicas
kubectl get volumes.longhorn.io -n longhorn-system \
  -o custom-columns='NAME:.metadata.name,REPLICAS:.spec.numberOfReplicas'
# All should show: 3

# Check all PVCs are Bound
kubectl get pvc --all-namespaces | grep -v Bound
# (should be empty)
```

---

## 🚀 Commit Changes

```bash
git add k8s/infrastructure/longhorn/
git status
git commit -m 'feat(storage): consolidate to single unified longhorn StorageClass

- Removed longhorn-wffc-storageclass.yaml (configuration drift)
- Created unified longhorn-storageclass.yaml:
  * 3 replicas for all new volumes
  * WaitForFirstConsumer binding
  * best-effort data locality
  * Default StorageClass
- Updated kustomization.yaml to reference single StorageClass

All 17 existing PVCs continue working (volumes have 3 replicas).
New PVCs will automatically use unified StorageClass.

Resolves multi-StorageClass confusion and ensures single source of truth.'

git push
```

---

## 📝 Lessons Learned

1. **StorageClass parameters are immutable** - can't update in-place
2. **Deleting StorageClass doesn't affect bound PVCs** - safe but alarming
3. **Multiple StorageClasses = configuration drift** - stick to one!
4. **expand-replicas-job.yaml is critical** - ensures all volumes have 3 replicas regardless of which StorageClass created them

**Thank you for catching this!** Single StorageClass = much cleaner.

