mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-11 00:05:01 +00:00
pg_provisioning.go covers cloud_credentials, provisioning_templates, provisioning_jobs, and provisioning_policy. Job repo exposes the state machine helpers the orchestrator needs (UpdateState, RecordServer, AppendIPs, AppendWorkerIDs, MarkFailed, MarkCompleted) so the package doesn't reach through *db.DB itself. pg_decision_log.go is a thin insert + recent-history reader for the audit trail powering the admin Decisions page.
114 lines
3.1 KiB
Go
114 lines
3.1 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/warmbly/warmbly/internal/infrastructure/db"
|
|
)
|
|
|
|
// DecisionLog is one automated action the system took (assignment,
|
|
// rebalance, quarantine, provisioning, IP rotation). Powers the admin
|
|
// "Decisions" page and post-hoc audit.
|
|
type DecisionLog struct {
|
|
ID int64
|
|
Kind string
|
|
WorkerID *uuid.UUID
|
|
MailboxID *uuid.UUID
|
|
Before json.RawMessage
|
|
After json.RawMessage
|
|
Reason string
|
|
TriggeredBy string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type DecisionLogRepository interface {
|
|
Insert(ctx context.Context, d *DecisionLog) error
|
|
ListRecent(ctx context.Context, kind string, limit int) ([]DecisionLog, error)
|
|
ListForWorker(ctx context.Context, workerID uuid.UUID, limit int) ([]DecisionLog, error)
|
|
}
|
|
|
|
type decisionLogRepository struct{ db *db.DB }
|
|
|
|
func NewDecisionLogRepository(d *db.DB) DecisionLogRepository {
|
|
return &decisionLogRepository{db: d}
|
|
}
|
|
|
|
func (r *decisionLogRepository) Insert(ctx context.Context, d *DecisionLog) error {
|
|
const q = `
|
|
INSERT INTO decision_log (kind, worker_id, mailbox_id, before, after, reason, triggered_by)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
RETURNING id, created_at
|
|
`
|
|
var before, after []byte
|
|
if len(d.Before) > 0 {
|
|
before = []byte(d.Before)
|
|
}
|
|
if len(d.After) > 0 {
|
|
after = []byte(d.After)
|
|
}
|
|
return r.db.QueryRow(ctx, q, d.Kind, d.WorkerID, d.MailboxID, before, after, d.Reason, d.TriggeredBy).
|
|
Scan(&d.ID, &d.CreatedAt)
|
|
}
|
|
|
|
func (r *decisionLogRepository) ListRecent(ctx context.Context, kind string, limit int) ([]DecisionLog, error) {
|
|
if limit <= 0 {
|
|
limit = 100
|
|
}
|
|
q := `SELECT id, kind, worker_id, mailbox_id, before, after, reason, triggered_by, created_at
|
|
FROM decision_log`
|
|
args := []any{}
|
|
if kind != "" {
|
|
q += ` WHERE kind = $1 ORDER BY created_at DESC LIMIT $2`
|
|
args = append(args, kind, limit)
|
|
} else {
|
|
q += ` ORDER BY created_at DESC LIMIT $1`
|
|
args = append(args, limit)
|
|
}
|
|
rows, err := r.db.Query(ctx, q, args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var out []DecisionLog
|
|
for rows.Next() {
|
|
var d DecisionLog
|
|
var before, after []byte
|
|
if err := rows.Scan(&d.ID, &d.Kind, &d.WorkerID, &d.MailboxID, &before, &after, &d.Reason, &d.TriggeredBy, &d.CreatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
d.Before = before
|
|
d.After = after
|
|
out = append(out, d)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
func (r *decisionLogRepository) ListForWorker(ctx context.Context, workerID uuid.UUID, limit int) ([]DecisionLog, error) {
|
|
if limit <= 0 {
|
|
limit = 100
|
|
}
|
|
rows, err := r.db.Query(ctx,
|
|
`SELECT id, kind, worker_id, mailbox_id, before, after, reason, triggered_by, created_at
|
|
FROM decision_log WHERE worker_id = $1 ORDER BY created_at DESC LIMIT $2`,
|
|
workerID, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var out []DecisionLog
|
|
for rows.Next() {
|
|
var d DecisionLog
|
|
var before, after []byte
|
|
if err := rows.Scan(&d.ID, &d.Kind, &d.WorkerID, &d.MailboxID, &before, &after, &d.Reason, &d.TriggeredBy, &d.CreatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
d.Before = before
|
|
d.After = after
|
|
out = append(out, d)
|
|
}
|
|
return out, rows.Err()
|
|
}
|