146 lines
4.4 KiB
Go
146 lines
4.4 KiB
Go
package brain_control
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"regexp"
|
|
"time"
|
|
)
|
|
|
|
type runtimeStatus struct {
|
|
SchemaVersion string `json:"schema_version"`
|
|
StatusID string `json:"status_id"`
|
|
BrainInstanceRef string `json:"brain_instance_ref"`
|
|
Sequence int64 `json:"sequence"`
|
|
ObservedAt time.Time `json:"observed_at"`
|
|
Runtime struct {
|
|
State string `json:"state"`
|
|
Version string `json:"version"`
|
|
StartedAt *time.Time `json:"started_at"`
|
|
} `json:"runtime"`
|
|
Model struct {
|
|
ModelRef string `json:"model_ref"`
|
|
Version string `json:"version"`
|
|
} `json:"model"`
|
|
Configurations []configurationStatus `json:"configurations"`
|
|
Health healthStatus `json:"health"`
|
|
Inputs []inputStatus `json:"inputs"`
|
|
}
|
|
type configurationStatus struct {
|
|
ConfigID string `json:"config_id"`
|
|
ApplyState string `json:"apply_state"`
|
|
AppliedRevision *int64 `json:"applied_revision"`
|
|
ErrorCode *string `json:"error_code"`
|
|
}
|
|
type metrics struct {
|
|
LoadPercent float64 `json:"load_percent"`
|
|
QueueDepth int64 `json:"queue_depth"`
|
|
LatencyMS float64 `json:"latency_ms"`
|
|
}
|
|
type healthStatus struct {
|
|
Overall string `json:"overall"`
|
|
ErrorCodes []string `json:"error_codes"`
|
|
Metrics metrics `json:"metrics"`
|
|
}
|
|
type inputStatus struct {
|
|
InputRef string `json:"input_ref"`
|
|
State string `json:"state"`
|
|
ErrorCodes []string `json:"error_codes"`
|
|
Metrics metrics `json:"metrics"`
|
|
}
|
|
|
|
var uuid4 = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)
|
|
var errCode = regexp.MustCompile(`^[A-Z][A-Z0-9_]{2,63}$`)
|
|
|
|
func parseRuntimeStatus(raw []byte) (runtimeStatus, error) {
|
|
var s runtimeStatus
|
|
d := json.NewDecoder(bytes.NewReader(raw))
|
|
d.DisallowUnknownFields()
|
|
if err := d.Decode(&s); err != nil {
|
|
return s, errors.New("CONFIG_INVALID")
|
|
}
|
|
if err := d.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
|
|
return s, errors.New("CONFIG_INVALID")
|
|
}
|
|
if s.SchemaVersion != RuntimeStatusVersion {
|
|
return s, errors.New("UNSUPPORTED_SCHEMA_VERSION")
|
|
}
|
|
if !uuid4.MatchString(s.StatusID) || !stableID.MatchString(s.BrainInstanceRef) || s.Sequence < 0 || s.ObservedAt.IsZero() || !validState(s.Runtime.State) || s.Runtime.Version == "" || !stableID.MatchString(s.Model.ModelRef) || s.Model.Version == "" || len(s.Configurations) > 4096 || len(s.Inputs) > 4096 || !validHealth(s.Health) {
|
|
return s, errors.New("CONFIG_INVALID")
|
|
}
|
|
seen := map[string]bool{}
|
|
for _, c := range s.Configurations {
|
|
if !stableID.MatchString(c.ConfigID) || seen[c.ConfigID] || !validApply(c) {
|
|
return s, errors.New("CONFIG_INVALID")
|
|
}
|
|
seen[c.ConfigID] = true
|
|
}
|
|
for _, i := range s.Inputs {
|
|
if !stableID.MatchString(i.InputRef) || !validState(i.State) || !validMetrics(i.Metrics) || !validCodes(i.ErrorCodes, 16) {
|
|
return s, errors.New("CONFIG_INVALID")
|
|
}
|
|
}
|
|
return s, nil
|
|
}
|
|
func validState(v string) bool {
|
|
switch v {
|
|
case "unconfigured", "starting", "running", "degraded", "failed", "stopped":
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
func validApply(c configurationStatus) bool {
|
|
switch c.ApplyState {
|
|
case "not_configured":
|
|
return c.AppliedRevision == nil
|
|
case "applying":
|
|
return true
|
|
case "applied":
|
|
return c.AppliedRevision != nil && *c.AppliedRevision >= 1
|
|
case "rejected":
|
|
return c.ErrorCode != nil && errCode.MatchString(*c.ErrorCode)
|
|
}
|
|
return false
|
|
}
|
|
func validMetrics(m metrics) bool {
|
|
return m.LoadPercent >= 0 && m.LoadPercent <= 100 && m.QueueDepth >= 0 && m.LatencyMS >= 0
|
|
}
|
|
func validCodes(v []string, n int) bool {
|
|
if len(v) > n {
|
|
return false
|
|
}
|
|
seen := map[string]bool{}
|
|
for _, x := range v {
|
|
if seen[x] || !errCode.MatchString(x) {
|
|
return false
|
|
}
|
|
seen[x] = true
|
|
}
|
|
return true
|
|
}
|
|
func validHealth(h healthStatus) bool {
|
|
return (h.Overall == "healthy" || h.Overall == "degraded" || h.Overall == "unhealthy") && validCodes(h.ErrorCodes, 32) && validMetrics(h.Metrics)
|
|
}
|
|
func validRuntimeTransition(from, to string) bool {
|
|
if from == to {
|
|
return true
|
|
}
|
|
switch from {
|
|
case "unconfigured":
|
|
return to == "starting" || to == "stopped"
|
|
case "starting":
|
|
return to == "running" || to == "degraded" || to == "failed" || to == "stopped"
|
|
case "running":
|
|
return to == "degraded" || to == "failed" || to == "stopped"
|
|
case "degraded":
|
|
return to == "running" || to == "failed" || to == "stopped"
|
|
case "failed":
|
|
return to == "starting" || to == "stopped"
|
|
case "stopped":
|
|
return to == "starting"
|
|
}
|
|
return false
|
|
}
|