Scope log retention deletion to selected hosts, not the whole table
api/logretention no longer deletes wholesale by age alone: a new
GET /logs/retention/hosts lists every host with matching records (plus
any configured retention floor), and preview/delete now require an
explicit, non-empty host list -- there is no "omitted host means every
host" shortcut server-side. Store's count/delete statements are
host-scoped (host IN (...)); Handler.partitionHosts checks the floor
per host instead of one global max, so a floor on one host never
blocks acting on other hosts requested in the same call. A request
that ends up fully or partially blocked still returns 200 with
blocked_hosts explaining why, rather than rejecting the whole call.
Settings' Log retention section is a host picker now: checkboxes with
per-host counts and a "protected Nd" badge where a floor applies,
"select all/none", and a confirm panel that names exactly which hosts
will be affected and which were skipped and why.
Verified live against real ClickHouse/Postgres and in-browser: three
hosts seeded, one protected by a 90-day floor -- a scoped delete
correctly removed the two open hosts' records, left the protected
host's untouched, and the response/UI both named it as skipped. Also
fixed a real spacing bug in the result message caught during that
browser pass (an adjacent {expr}{#if} with no source whitespace
between them rendered with no space either).
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// AgentRetentionStore reads the protective retention floor set on
|
||||
// AgentRetentionStore reads the protective retention floors set on
|
||||
// agents.ConfigOverride.LogRetentionDays -- a separate, Postgres-backed
|
||||
// concern from Store's ClickHouse access above, so it lives in its own
|
||||
// file. Deliberately its own narrow query against the same `agents`
|
||||
@@ -23,24 +23,31 @@ func NewAgentRetentionStore(pool *pgxpool.Pool) *AgentRetentionStore {
|
||||
return &AgentRetentionStore{pool: pool}
|
||||
}
|
||||
|
||||
// MaxRetentionDays reports the largest log_retention_days configured
|
||||
// across any agent's desired_override, if any are set at all -- this is
|
||||
// the floor a non-owner's deletion request must not reach into (see
|
||||
// Handler.checkRetentionFloor). The second return value is false when
|
||||
// no agent has this field configured, distinct from a configured floor
|
||||
// of 0 (which validateOverride never allows to be stored in the first
|
||||
// place).
|
||||
func (s *AgentRetentionStore) MaxRetentionDays(ctx context.Context) (int, bool, error) {
|
||||
var days *int
|
||||
err := s.pool.QueryRow(ctx, `
|
||||
SELECT max((desired_override->>'log_retention_days')::int)
|
||||
// RetentionDaysByHost reports the configured log_retention_days for
|
||||
// every agent that has one set, keyed by host -- a host absent from
|
||||
// this map has no configured floor at all. Per-host rather than a
|
||||
// single global maximum: now that deletion is host-scoped
|
||||
// (Handler.partitionHosts), a floor on one host must never block
|
||||
// deleting another host's logs that happen to be requested in the same
|
||||
// call.
|
||||
func (s *AgentRetentionStore) RetentionDaysByHost(ctx context.Context) (map[string]int, error) {
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT host, (desired_override->>'log_retention_days')::int
|
||||
FROM agents
|
||||
WHERE desired_override->>'log_retention_days' IS NOT NULL`).Scan(&days)
|
||||
WHERE desired_override->>'log_retention_days' IS NOT NULL`)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
return nil, err
|
||||
}
|
||||
if days == nil {
|
||||
return 0, false, nil
|
||||
defer rows.Close()
|
||||
|
||||
out := map[string]int{}
|
||||
for rows.Next() {
|
||||
var host string
|
||||
var days int
|
||||
if err := rows.Scan(&host, &days); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[host] = days
|
||||
}
|
||||
return *days, true, nil
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user