cf3d98eb2b
R-022: orca job run now deploys to remote nodes via scheduler -> emitter -> SSH-push. Local exec fallback only when no remote nodes registered. jobspec parser (REQ-152): - schedule: and timeout: now parsed (were silently dropped) - DaemonSet Count no longer defaults to 1 (was breaking DaemonSet) - restart: policy translated to systemd Restart=/StartLimitBurst - job lint: advisory warnings for cron/health/update/affinity (honest) scheduler wiring (REQ-151, C-44): - new internal/cli/job_dispatch.go: dispatchDecision + deployRemote - scheduler.Schedule evaluates constraints/capacity/affinity - --target overrides scheduler (manual pinning) - local fallback only when len(ready non-localhost nodes)==0 - C-44: SSH-push failure returns error (no silent local fallback) - systemd-analyze verify on rendered unit before deploy Tests: 22 new test functions covering scheduler, parser, C-44, local fallback, target override, systemd-analyze skip, restart directives. ---ci--- project: orca phase: 3 milestone: v0.13 status: complete requirements: covered: [151, 152] ---/ci---
86 lines
2.4 KiB
Go
86 lines
2.4 KiB
Go
package emitter
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.cloudinit.dev/coreci/orca/internal/jobspec"
|
|
)
|
|
|
|
func TestSystemdEmitter_RestartNever(t *testing.T) {
|
|
spec := &jobspec.WorkloadSpec{
|
|
Kind: "Job",
|
|
Name: "one",
|
|
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/true"},
|
|
Restart: &jobspec.RestartBlock{Mode: "never"},
|
|
}
|
|
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
|
|
if err != nil {
|
|
t.Fatalf("Render: %v", err)
|
|
}
|
|
if !strings.Contains(files[0].Content, "Restart=no") {
|
|
t.Errorf("missing Restart=no:\n%s", files[0].Content)
|
|
}
|
|
}
|
|
|
|
func TestSystemdEmitter_RestartOnFailure(t *testing.T) {
|
|
spec := &jobspec.WorkloadSpec{
|
|
Kind: "Job",
|
|
Name: "retry",
|
|
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/true"},
|
|
Restart: &jobspec.RestartBlock{Mode: "on-failure", MaxRetries: 3, Delay: "5s"},
|
|
}
|
|
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
|
|
if err != nil {
|
|
t.Fatalf("Render: %v", err)
|
|
}
|
|
c := files[0].Content
|
|
if !strings.Contains(c, "Restart=on-failure") {
|
|
t.Errorf("missing Restart=on-failure:\n%s", c)
|
|
}
|
|
if !strings.Contains(c, "StartLimitBurst=3") {
|
|
t.Errorf("missing StartLimitBurst=3:\n%s", c)
|
|
}
|
|
if !strings.Contains(c, "RestartSec=5s") {
|
|
t.Errorf("missing RestartSec=5s:\n%s", c)
|
|
}
|
|
if !strings.Contains(c, "StartLimitIntervalSec=5s") {
|
|
t.Errorf("missing StartLimitIntervalSec=5s:\n%s", c)
|
|
}
|
|
}
|
|
|
|
func TestSystemdEmitter_RestartService(t *testing.T) {
|
|
spec := &jobspec.WorkloadSpec{
|
|
Kind: "Service",
|
|
Name: "web",
|
|
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/httpd"},
|
|
Restart: &jobspec.RestartBlock{Mode: "service", MaxRetries: 5, Delay: "10s"},
|
|
}
|
|
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
|
|
if err != nil {
|
|
t.Fatalf("Render: %v", err)
|
|
}
|
|
c := files[0].Content
|
|
if !strings.Contains(c, "Restart=always") {
|
|
t.Errorf("missing Restart=always:\n%s", c)
|
|
}
|
|
if !strings.Contains(c, "StartLimitBurst=5") {
|
|
t.Errorf("missing StartLimitBurst=5:\n%s", c)
|
|
}
|
|
}
|
|
|
|
func TestSystemdEmitter_RestartNilOmitted(t *testing.T) {
|
|
spec := &jobspec.WorkloadSpec{
|
|
Kind: "Job",
|
|
Name: "norest",
|
|
Runtime: &jobspec.RuntimeBlock{OneOf: "process", Command: "/bin/true"},
|
|
}
|
|
files, err := SystemdEmitter{}.Render(spec, &Node{Hostname: "n"})
|
|
if err != nil {
|
|
t.Fatalf("Render: %v", err)
|
|
}
|
|
if strings.Contains(files[0].Content, "Restart=") {
|
|
t.Errorf("nil Restart should omit Restart= line:\n%s", files[0].Content)
|
|
}
|
|
}
|