feat(P02): node management with SQLite-backed registry
Implements Phase 2 of v0.1 Foundation:
- internal/model/node.go: Node struct with state machine (pending/ready/left)
- internal/store/store.go: SQLite open with WAL + foreign_keys pragmas
- internal/store/migrate.go: embedded SQL migration runner
- internal/store/migrations/0001_nodes.sql: nodes table schema
- internal/store/node_repo.go: CRUD operations for nodes
- internal/store/node_repo_test.go: 4 tests covering insert/get/list/update/delete
- internal/engine/registry.go: in-memory wrapper with slog audit logging
- internal/cli/node.go: orca node {join,leave,list} wired to registry
Verified: node join/list/leave work end-to-end, JSON output, slog audit logs,
state persists in SQLite, all tests pass with -race.
---ci---
project: orca
phase: 2
milestone: v0.1
status: execute
req_covered:
- REQ-002
- REQ-005
- REQ-008
- REQ-012
- REQ-017
- REQ-018
---/ci---
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"git.cloudinit.dev/coreci/orca/internal/model"
|
||||
"git.cloudinit.dev/coreci/orca/internal/store"
|
||||
)
|
||||
|
||||
type NodeRegistry struct {
|
||||
repo *store.NodeRepo
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
func NewNodeRegistry(repo *store.NodeRepo, log *slog.Logger) *NodeRegistry {
|
||||
if log == nil {
|
||||
log = slog.Default()
|
||||
}
|
||||
return &NodeRegistry{repo: repo, log: log}
|
||||
}
|
||||
|
||||
func (r *NodeRegistry) Join(ctx context.Context, n *model.Node) error {
|
||||
if err := r.repo.Insert(ctx, n); err != nil {
|
||||
return fmt.Errorf("join node: %w", err)
|
||||
}
|
||||
r.log.Info("node joined",
|
||||
slog.String("node_id", n.ID),
|
||||
slog.String("name", n.Name),
|
||||
slog.String("address", n.Address))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *NodeRegistry) Leave(ctx context.Context, id string) error {
|
||||
if err := r.repo.UpdateState(ctx, id, model.NodeStateLeft); err != nil {
|
||||
return fmt.Errorf("leave node: %w", err)
|
||||
}
|
||||
r.log.Info("node left", slog.String("node_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *NodeRegistry) Forget(ctx context.Context, id string) error {
|
||||
if err := r.repo.Delete(ctx, id); err != nil {
|
||||
return fmt.Errorf("forget node: %w", err)
|
||||
}
|
||||
r.log.Info("node removed from registry", slog.String("node_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *NodeRegistry) List(ctx context.Context) ([]*model.Node, error) {
|
||||
return r.repo.List(ctx)
|
||||
}
|
||||
|
||||
func (r *NodeRegistry) Get(ctx context.Context, id string) (*model.Node, error) {
|
||||
return r.repo.Get(ctx, id)
|
||||
}
|
||||
Reference in New Issue
Block a user