api

package
v0.1.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AcceptanceRunHandler

func AcceptanceRunHandler(repoDir string) http.HandlerFunc

AcceptanceRunHandler — GET /api/acceptance-run?server=<id>

Streams scripts/acceptance-test.sh against the chosen server over SSH tunnels (data-plane :engine_port and control-plane :9090). Each output line is delivered as an SSE "line" event; a final "done" event carries the exit code and pass/fail/info counts. Concurrent runs against the same server are rejected with 409 to prevent test interference.

func BenchCompareGroupsHandler

func BenchCompareGroupsHandler(w http.ResponseWriter, r *http.Request)

BenchCompareGroupsHandler — POST /api/bench/compare-groups body: {"label_a":"baseline-x","label_b":"candidato-y"}

func BenchCompareHandler

func BenchCompareHandler(w http.ResponseWriter, r *http.Request)

BenchCompareHandler — POST /api/bench/compare body: {"run_a":1,"run_b":2}

func BenchComparisonsHandler

func BenchComparisonsHandler(w http.ResponseWriter, r *http.Request)

BenchComparisonsHandler — GET /api/bench/comparisons → comparison history.

func BenchExportHandler

func BenchExportHandler(w http.ResponseWriter, r *http.Request)

BenchExportHandler — GET /api/bench/export?prefix=pub- Streams every run whose label starts with the prefix as CSV (raw evidence for published benchmarks; error_rate included because the saturation criterion depends on it).

func BenchImportHandler

func BenchImportHandler(w http.ResponseWriter, r *http.Request)

BenchImportHandler — POST /api/bench/import body: {"path":"/tmp/k6-run.json","label":"...","rps":500,"duration":30}

func BenchProtocolHandler

func BenchProtocolHandler(repoDir string) http.HandlerFunc

BenchProtocolHandler — POST /api/bench/protocol body: {"runs":3,"label":"ui-test","rate":50,"duration":"15s",

"script":"sustained_writes.js","server_id":2}

script is optional (default sustained_2krps.js) and must be one of the protocolScripts allowlist keys — never a path.

server_id is optional: when set, the run targets that registered server's engine (TARGET_URL) and the label is prefixed "{server_name}--" so groups from different servers stay distinguishable yet comparable. k6 ALWAYS runs on this box — the loader never competes for CPU with the system under test (S46 methodology).

Runs scripts/bench-protocol.sh and streams its stdout/stderr as SSE, ending with an `event: done` carrying the exit code.

SECURITY: every field is validated against a strict allowlist before use, and the validated values are passed as SEPARATE argv elements to exec.Command — never concatenated into a shell string. There is no path to `sh -c` here, so even if a regex were loosened the values still cannot break out into the shell.

func BenchRunHistogramHandler

func BenchRunHistogramHandler(w http.ResponseWriter, r *http.Request)

BenchRunHistogramHandler — GET /api/bench/runs/{id}/histogram Returns 1ms-wide buckets aggregated in SQL (never ships raw datapoints).

func BenchRunStatsHandler

func BenchRunStatsHandler(w http.ResponseWriter, r *http.Request)

BenchRunStatsHandler — GET /api/bench/runs/{id}/stats Quartile/boxplot summary for one run (cached). Never ships raw datapoints.

func BenchRunsHandler

func BenchRunsHandler(w http.ResponseWriter, r *http.Request)

BenchRunsHandler — GET /api/bench/runs → list benchmark_runs (no datapoints).

func DeployHandler

func DeployHandler(repoDir string) http.HandlerFunc

DeployHandler — POST /api/deploy body: {"server_id":2,"confirm":"58-prod"}

func DeploysListHandler

func DeploysListHandler(w http.ResponseWriter, r *http.Request)

DeploysListHandler — GET /api/deploys?server_id=

func InitBenchDB

func InitBenchDB(repoDir, schemaSQL string) error

InitBenchDB opens (creating if needed) the SQLite store at <repoDir>/tools/devhub/db/devhub.db and applies the embedded schema. The schema is idempotent (CREATE TABLE IF NOT EXISTS / INSERT OR IGNORE), so it is safe to run on every boot. schemaSQL is the contents of db/schema.sql, passed in from the main package (which can embed it — the api package cannot reach a sibling directory with go:embed).

func InitSecrets

func InitSecrets(store *secrets.Store)

InitSecrets connects the age store and routes its usage audit into SQLite.

func MetricsLiveHandler

func MetricsLiveHandler(w http.ResponseWriter, r *http.Request)

func MetricsLiveRouter

func MetricsLiveRouter(w http.ResponseWriter, r *http.Request)

MetricsLiveRouter — GET /api/metrics/live?server={id} No server param (or a local server) → the existing local ring stream; a remote server id → the on-demand tunnel scrape stream.

func MetricsSnapshotHandler

func MetricsSnapshotHandler(w http.ResponseWriter, r *http.Request)

func ParseK6JSON

func ParseK6JSON(path string) (latencies []float64, errorRate float64, err error)

ParseK6JSON streams a k6 NDJSON file line by line (never loading the whole file — it can be >100MB) and returns the http_req_duration latencies in ms for successful requests, plus the error rate. A request is "successful" when its expected_response tag is not "false" (k6 tags failed responses expected_response:"false"); the error rate is failed / total over all http_req_duration points.

func RunHandler

func RunHandler(repoDir string) http.HandlerFunc

func SecretAuditHandler

func SecretAuditHandler(w http.ResponseWriter, r *http.Request)

SecretAuditHandler — GET /api/audit/secrets?server_id=

func ServerDeleteAdminKeyHandler

func ServerDeleteAdminKeyHandler(w http.ResponseWriter, r *http.Request)

ServerDeleteAdminKeyHandler — DELETE /api/servers/{id}/admin-key (rotation).

func ServerFetchAdminKeyHandler

func ServerFetchAdminKeyHandler(w http.ResponseWriter, r *http.Request)

ServerFetchAdminKeyHandler — POST /api/servers/{id}/fetch-admin-key The human's click IS the authorization: the DevHub reads ADMIN_KEY from the server's own secrets file over SSH (fixed command, validated path) and stores it encrypted. The value never appears in the response, logs or DB.

func ServerSecretStatusHandler

func ServerSecretStatusHandler(w http.ResponseWriter, r *http.Request)

ServerSecretStatusHandler — GET /api/servers/{id}/secret-status The only thing the API reveals about a secret: whether one exists, and where it would come from. Never the value.

func ServerSetAdminKeyHandler

func ServerSetAdminKeyHandler(w http.ResponseWriter, r *http.Request)

ServerSetAdminKeyHandler — PUT /api/servers/{id}/admin-key body {"value":"..."} Manual load for servers where the SSH fetch does not apply.

func ServersCreateHandler

func ServersCreateHandler(w http.ResponseWriter, r *http.Request)

ServersCreateHandler — POST /api/servers

func ServersDeleteHandler

func ServersDeleteHandler(w http.ResponseWriter, r *http.Request)

ServersDeleteHandler — DELETE /api/servers/{id}

func ServersListHandler

func ServersListHandler(w http.ResponseWriter, r *http.Request)

ServersListHandler — GET /api/servers

func ServersTestHandler

func ServersTestHandler(w http.ResponseWriter, r *http.Request)

ServersTestHandler — POST /api/servers/{id}/test Dials the server (TOFU-pinning the host key on first connect), runs the fixed identification commands and probes the engine's /health through an SSH tunnel. Pure read-only diagnostics.

func StartMetricsScraper

func StartMetricsScraper()

Types

type CompareResult

type CompareResult struct {
	RunA        int64   `json:"run_a"`
	RunB        int64   `json:"run_b"`
	U           float64 `json:"u"`
	PValue      float64 `json:"p_value"`
	CILowerMs   float64 `json:"ci_lower_ms"`
	CIUpperMs   float64 `json:"ci_upper_ms"`
	MinEffectMs float64 `json:"min_effect_ms"`
	Significant bool    `json:"significant"`
	Direction   string  `json:"direction"`
	DeltaPct    float64 `json:"delta_pct"`
}

CompareResult is the outcome of CompareRuns, mirroring the comparisons table (plus min_effect_ms, which is reported for transparency but not persisted).

func CompareRuns

func CompareRuns(runA, runB int64) (*CompareResult, error)

CompareRuns loads both runs' datapoints, classifies the comparison (see classify) and persists it. Returns the verdict.

type GroupCompareResult

type GroupCompareResult struct {
	LabelA         string  `json:"label_a"`
	LabelB         string  `json:"label_b"`
	ServerA        string  `json:"server_a"` // parsed from the "{server}--" label prefix
	ServerB        string  `json:"server_b"`
	NRunsA         int     `json:"n_runs_a"`
	NRunsB         int     `json:"n_runs_b"`
	NA             int     `json:"n_a"` // pooled datapoints after per-run IQR rejection
	NB             int     `json:"n_b"`
	CVBetweenRunsA float64 `json:"cv_between_runs_a"`
	CVBetweenRunsB float64 `json:"cv_between_runs_b"`
	U              float64 `json:"u"`
	PValue         float64 `json:"p_value"`
	CILowerMs      float64 `json:"ci_lower_ms"`
	CIUpperMs      float64 `json:"ci_upper_ms"`
	MinEffectMs    float64 `json:"min_effect_ms"`
	Significant    bool    `json:"significant"`
	Direction      string  `json:"direction"`
	DeltaPct       float64 `json:"delta_pct"`
}

GroupCompareResult is the verdict for a label-vs-label comparison. It carries the same statistical fields as CompareResult plus group metadata: how many runs each label pooled, the pooled datapoint counts, and each group's between-run CV (the run-to-run reproducibility of the p50). This is the defensible "N runs vs M runs" comparison, as opposed to single run vs run.

func CompareGroups

func CompareGroups(labelA, labelB string) (*GroupCompareResult, error)

CompareGroups pools every run of label A and label B (IQR-rejecting each run first) and runs the same verdict (Mann-Whitney + bootstrap CI + practical min-effect) on the two pools. Comparing a label against itself yields no_change (identical pools → zero median shift). Not persisted: the comparisons table is keyed on single run ids.

type MetricSample

type MetricSample struct {
	TS            int64   `json:"ts"`
	RequestsTotal float64 `json:"requests_total"`
	P95Ms         float64 `json:"p95_ms"`
	ActiveTenants float64 `json:"active_tenants"`
	MotorUp       bool    `json:"motor_up"`
}

type RegisteredServer

type RegisteredServer struct {
	sshx.Server
	EnginePort   int
	AdminKeyEnv  string
	IsProduction bool
	BenchTenant  string
	SecretsPath  string
	StartScript  string
	BinaryPath   string
	LogPath      string
	CreatedAt    string
}

RegisteredServer is a row of the servers table plus its sshx identity. The SSH key is exposed to API consumers as its basename only — the full path stays server-side and the key material never leaves the filesystem.

func LoadServer

func LoadServer(id int64) (*RegisteredServer, error)

LoadServer fetches one registered server by id.

func (*RegisteredServer) AdminKey

func (s *RegisteredServer) AdminKey() string

AdminKey resolves the server's engine admin key from the devhub process environment (admin_key_env names the variable; secrets never live in SQLite).

func (*RegisteredServer) EngineURL

func (s *RegisteredServer) EngineURL() string

EngineURL is the direct (untunneled) base URL of the server's engine — what an external load generator should hit.

type RunStats

type RunStats struct {
	RunID       int64   `json:"run_id"`
	Min         float64 `json:"min"`
	Q1          float64 `json:"q1"`
	Median      float64 `json:"median"`
	Q3          float64 `json:"q3"`
	Max         float64 `json:"max"`
	P95         float64 `json:"p95"`
	P99         float64 `json:"p99"`
	N           int     `json:"n"`
	OutliersIQR int     `json:"outliers_iqr"`
}

RunStats is the five-number boxplot summary of a run plus the tail percentiles and IQR-outlier count. Computed in Go (SQLite has no native percentile) and cached: a run's datapoints are immutable, so the summary never changes.

type RunSummary

type RunSummary struct {
	RunID     int64   `json:"run_id"`
	Label     string  `json:"label"`
	TargetRPS int     `json:"target_rps"`
	DurationS int     `json:"duration_s"`
	N         int     `json:"n_requests"`
	P50       float64 `json:"p50_ms"`
	P95       float64 `json:"p95_ms"`
	P99       float64 `json:"p99_ms"`
	ErrorRate float64 `json:"error_rate"`
	CV        float64 `json:"cv"`
}

RunSummary is the row written to benchmark_runs plus its id.

func SaveRun

func SaveRun(label string, rps, durationS int, latencies []float64, errorRate float64) (*RunSummary, error)

SaveRun computes the summary percentiles/CV from latencies and persists the run plus every datapoint (batched). Returns the stored summary with its id.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL