feat(P02): Service block + Traefik emitter + atomic reload (REQ-077, gate C-10)
P02 — Traefik dynamic config generation + atomic reload protocol. Parser (internal/jobspec/markdown.go): - Extended WorkloadSpec with Health, Constraints, Affinity, Lifecycle fields. Parsed restart/update/service/health/lifecycle/affinity/ constraints blocks. HealthBlock, AffinityRule, LifecycleBlock types. Schema (internal/spec/schema/schema.go): - ServiceValidator: restart.mode enum (service/on-failure/never), update.strategy enum (rolling/canary/blue-green), health required, service.bind IP validation (R-007 loopback opt-in). 98.5% coverage. Traefik emitter (internal/emitter/traefik.go, REQ-077): - TraefikEmitter renders /etc/traefik/dynamic/orca-<name>.yaml with http.routers, http.services (servers = R-007 socket paths), TLS (certResolver=orca, trust domain), healthCheck. RenderDrain sets weight:0 per backend. RegisterTraefik wires process/podman/wasm. Atomic reload (internal/emitter/traefik_atomic.go, gate C-10): - WriteTraefikDynamic: write to path.tmp via WriteFileIdempotent, then mv -f path.tmp path (atomic POSIX rename, Traefik fsnotify observes IN_MOVED_TO). Traefik holds-last-good on malformed config. C-10 PASS. 22 packages pass, 20 bats pass, gofmt clean, verify-reqs 90 consistent. Coverage: emitter 96.5%, jobspec 88.8%, schema 98.5%, sshpush 93.0%. ---ci--- project: orca phase: P02 milestone: v0.9 status: execute ---/ci---
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
// Package sshpush_test contains compile-time assertions that *Transport
|
||||
// satisfies the emitter.AtomicWriter interface (the Traefik C-10
|
||||
// atomicity protocol — internal/emitter/traefik_atomic.go). The
|
||||
// assertion lives here (not in internal/emitter) to avoid an import
|
||||
// cycle: internal/emitter is imported by this package (fanout.go), so
|
||||
// internal/emitter cannot import this package.
|
||||
package sshpush_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"git.cloudinit.dev/coreci/orca/internal/emitter"
|
||||
"git.cloudinit.dev/coreci/orca/internal/sshpush"
|
||||
)
|
||||
|
||||
// Compile-time assertion: *sshpush.Transport satisfies
|
||||
// emitter.AtomicWriter. WriteTraefikDynamic relies on this so the
|
||||
// Traefik dynamic-config file is written atomically (gate C-10).
|
||||
var _ emitter.AtomicWriter = (*sshpush.Transport)(nil)
|
||||
|
||||
func TestTransportSatisfiesAtomicWriter(t *testing.T) {
|
||||
// A trivial runtime check that the type conversion is valid; the
|
||||
// compile-time assertion above is the real test, but this gives
|
||||
// `go test` a function to run.
|
||||
tr := sshpush.NewTransport("/nonexistent", "/nonexistent")
|
||||
var w emitter.AtomicWriter = tr
|
||||
_ = w
|
||||
_ = context.Background()
|
||||
}
|
||||
Reference in New Issue
Block a user