layer1: derive namespace phases step 10
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
# 2026-04-26 — NamespaceManager rewrite, step 10
|
||||||
|
|
||||||
|
## Цель шага
|
||||||
|
|
||||||
|
Научить skeleton manager выводить общую phase namespace-а из part states.
|
||||||
|
|
||||||
|
## Что меняем
|
||||||
|
|
||||||
|
1. Добавляем константы состояний частей:
|
||||||
|
- `registering`
|
||||||
|
- `active`
|
||||||
|
- `failed`
|
||||||
|
2. После `MarkPartState()` manager пересчитывает общую phase namespace-а.
|
||||||
|
3. Добавляем unit tests на переходы:
|
||||||
|
- registering -> active
|
||||||
|
- failed -> NamespacePhaseFailed
|
||||||
|
|
||||||
|
## Что НЕ меняем
|
||||||
|
|
||||||
|
- не запускаем реальный reconcile loop;
|
||||||
|
- не вызываем subscriber-ов автоматически;
|
||||||
|
- не подключаем manager к runtime.
|
||||||
@@ -152,6 +152,7 @@ func (m *inMemoryNamespaceManager) MarkPartState(namespace string, part string,
|
|||||||
state.UpdatedAt = time.Now().UTC()
|
state.UpdatedAt = time.Now().UTC()
|
||||||
}
|
}
|
||||||
record.RegisteredParts[part] = state
|
record.RegisteredParts[part] = state
|
||||||
|
record.Phase = deriveNamespacePhase(record)
|
||||||
record.UpdatedAt = state.UpdatedAt
|
record.UpdatedAt = state.UpdatedAt
|
||||||
m.records[namespace] = record
|
m.records[namespace] = record
|
||||||
return record.Clone(), true
|
return record.Clone(), true
|
||||||
@@ -166,4 +167,30 @@ func (m *inMemoryNamespaceManager) Remove(name string) bool {
|
|||||||
}
|
}
|
||||||
delete(m.records, name)
|
delete(m.records, name)
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func deriveNamespacePhase(record NamespaceRecord) NamespacePhase {
|
||||||
|
if len(record.RegisteredParts) == 0 {
|
||||||
|
return record.Phase
|
||||||
|
}
|
||||||
|
|
||||||
|
hasRegistering := false
|
||||||
|
for _, part := range record.RegisteredParts {
|
||||||
|
switch part.State {
|
||||||
|
case NamespacePartStateFailed:
|
||||||
|
return NamespacePhaseFailed
|
||||||
|
case NamespacePartStateRegistering:
|
||||||
|
hasRegistering = true
|
||||||
|
case NamespacePartStateActive:
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
hasRegistering = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasRegistering {
|
||||||
|
return NamespacePhaseRegistering
|
||||||
|
}
|
||||||
|
|
||||||
|
return NamespacePhaseActive
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,12 @@ package utils
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
NamespacePartStateRegistering string = "registering"
|
||||||
|
NamespacePartStateActive string = "active"
|
||||||
|
NamespacePartStateFailed string = "failed"
|
||||||
|
)
|
||||||
|
|
||||||
type NamespacePhase string
|
type NamespacePhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -53,13 +53,16 @@ func TestNamespaceManagerMarkPartState(t *testing.T) {
|
|||||||
manager := NewNamespaceManager()
|
manager := NewNamespaceManager()
|
||||||
manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})
|
manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})
|
||||||
|
|
||||||
record, ok := manager.MarkPartState("tenant-a", "router", NamespacePartState{State: "active"})
|
record, ok := manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateActive})
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected mark part state to succeed")
|
t.Fatalf("expected mark part state to succeed")
|
||||||
}
|
}
|
||||||
if record.RegisteredParts["router"].State != "active" {
|
if record.RegisteredParts["router"].State != NamespacePartStateActive {
|
||||||
t.Fatalf("expected router part state to be stored")
|
t.Fatalf("expected router part state to be stored")
|
||||||
}
|
}
|
||||||
|
if record.Phase != NamespacePhaseActive {
|
||||||
|
t.Fatalf("expected phase to become active, got %s", record.Phase)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNamespaceManagerRemove(t *testing.T) {
|
func TestNamespaceManagerRemove(t *testing.T) {
|
||||||
@@ -85,7 +88,7 @@ func TestNamespaceManagerSnapshotRecordsReturnsCopies(t *testing.T) {
|
|||||||
Source: NamespaceSourceWatcher,
|
Source: NamespaceSourceWatcher,
|
||||||
Labels: map[string]string{"fission.io/managed": "true"},
|
Labels: map[string]string{"fission.io/managed": "true"},
|
||||||
})
|
})
|
||||||
_, _ = manager.MarkPartState("tenant-a", "router", NamespacePartState{State: "active"})
|
_, _ = manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateActive})
|
||||||
|
|
||||||
records := manager.SnapshotRecords()
|
records := manager.SnapshotRecords()
|
||||||
records[0].Labels["fission.io/managed"] = "false"
|
records[0].Labels["fission.io/managed"] = "false"
|
||||||
@@ -98,7 +101,7 @@ func TestNamespaceManagerSnapshotRecordsReturnsCopies(t *testing.T) {
|
|||||||
if record.Labels["fission.io/managed"] != "true" {
|
if record.Labels["fission.io/managed"] != "true" {
|
||||||
t.Fatalf("expected snapshot records to be detached copies")
|
t.Fatalf("expected snapshot records to be detached copies")
|
||||||
}
|
}
|
||||||
if record.RegisteredParts["router"].State != "active" {
|
if record.RegisteredParts["router"].State != NamespacePartStateActive {
|
||||||
t.Fatalf("expected part states to be detached copies")
|
t.Fatalf("expected part states to be detached copies")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,4 +116,25 @@ func TestNamespaceManagerSubscribers(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(expected, manager.SnapshotSubscribers()) {
|
if !reflect.DeepEqual(expected, manager.SnapshotSubscribers()) {
|
||||||
t.Fatalf("expected subscribers %v, got %v", expected, manager.SnapshotSubscribers())
|
t.Fatalf("expected subscribers %v, got %v", expected, manager.SnapshotSubscribers())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamespaceManagerMarkPartStateDerivesPhase(t *testing.T) {
|
||||||
|
manager := NewNamespaceManager()
|
||||||
|
manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher})
|
||||||
|
|
||||||
|
record, ok := manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateRegistering})
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected registering state update to succeed")
|
||||||
|
}
|
||||||
|
if record.Phase != NamespacePhaseRegistering {
|
||||||
|
t.Fatalf("expected phase registering, got %s", record.Phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
record, ok = manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateFailed})
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected failed state update to succeed")
|
||||||
|
}
|
||||||
|
if record.Phase != NamespacePhaseFailed {
|
||||||
|
t.Fatalf("expected phase failed, got %s", record.Phase)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user