Post-repair hardware validation pipeline for Proxmox cluster hosts. Go orchestrator + in-image agent + mkosi live image + bundled dnsmasq PXE + SQLite + HTMX/SSE UI + notify registry + janitor + full docs.
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"vetting/internal/model"
|
||||
)
|
||||
|
||||
type Artifact struct {
|
||||
ID int64
|
||||
RunID int64
|
||||
StageID *int64
|
||||
Kind string // inventory|spec_diff|hold_key|report|log|fio|iperf|smart
|
||||
Path string
|
||||
SHA256 string
|
||||
SizeBytes int64
|
||||
}
|
||||
|
||||
type Artifacts struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
func (a *Artifacts) Create(ctx context.Context, art Artifact) (int64, error) {
|
||||
res, err := a.DB.ExecContext(ctx, `
|
||||
INSERT INTO artifacts(run_id, stage_id, kind, path, sha256, size_bytes)
|
||||
VALUES(?,?,?,?,?,?)
|
||||
`, art.RunID, nullInt64(art.StageID), art.Kind, art.Path, art.SHA256, art.SizeBytes)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("insert artifact: %w", err)
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
// DeleteForRun removes every artifact row for a run. Returns the rows
|
||||
// that were deleted so the caller can unlink the on-disk files. Used by
|
||||
// the janitor; ordinary flow treats artifacts as append-only.
|
||||
func (a *Artifacts) DeleteForRun(ctx context.Context, runID int64) ([]Artifact, error) {
|
||||
arts, err := a.ListForRun(ctx, runID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := a.DB.ExecContext(ctx, `DELETE FROM artifacts WHERE run_id = ?`, runID); err != nil {
|
||||
return nil, fmt.Errorf("delete artifacts for run %d: %w", runID, err)
|
||||
}
|
||||
return arts, nil
|
||||
}
|
||||
|
||||
func (a *Artifacts) ListForRun(ctx context.Context, runID int64) ([]Artifact, error) {
|
||||
rows, err := a.DB.QueryContext(ctx, `
|
||||
SELECT id, run_id, stage_id, kind, path, sha256, size_bytes
|
||||
FROM artifacts WHERE run_id = ? ORDER BY id
|
||||
`, runID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Artifact
|
||||
for rows.Next() {
|
||||
var ar Artifact
|
||||
var stageID sql.NullInt64
|
||||
if err := rows.Scan(&ar.ID, &ar.RunID, &stageID, &ar.Kind, &ar.Path, &ar.SHA256, &ar.SizeBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stageID.Valid {
|
||||
v := stageID.Int64
|
||||
ar.StageID = &v
|
||||
}
|
||||
out = append(out, ar)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
type SpecDiffs struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
func (s *SpecDiffs) ReplaceForRun(ctx context.Context, runID int64, diffs []model.SpecDiff) error {
|
||||
tx, err := s.DB.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
if _, err := tx.ExecContext(ctx, `DELETE FROM spec_diffs WHERE run_id = ?`, runID); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, d := range diffs {
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO spec_diffs(run_id, field, expected, actual, severity, ignored)
|
||||
VALUES(?,?,?,?,?,?)
|
||||
`, runID, d.Field, d.Expected, d.Actual, d.Severity, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *SpecDiffs) ListForRun(ctx context.Context, runID int64) ([]model.SpecDiff, error) {
|
||||
rows, err := s.DB.QueryContext(ctx, `
|
||||
SELECT id, run_id, field, COALESCE(expected,''), COALESCE(actual,''), severity, ignored
|
||||
FROM spec_diffs WHERE run_id = ? ORDER BY id
|
||||
`, runID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []model.SpecDiff
|
||||
for rows.Next() {
|
||||
var d model.SpecDiff
|
||||
var ignored int
|
||||
if err := rows.Scan(&d.ID, &d.RunID, &d.Field, &d.Expected, &d.Actual, &d.Severity, &ignored); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.Ignored = ignored != 0
|
||||
out = append(out, d)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func nullInt64(p *int64) any {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
return *p
|
||||
}
|
||||
Reference in New Issue
Block a user