功能:完善通用云管工作台、审计与诊断能力
This commit is contained in:
1 parent
5ac692724d
commit
9f05aa20ea
225 files changed
+14266
-141
No files matched your search
@@ -0,0 +1,52 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"vdi-cloud/platform/internal/store"
|
||||
)
|
||||
|
||||
// Column names are exclusively from this allowlist, never request text.
|
||||
func terminalAlertColumn(metric string) string {
|
||||
return map[string]string{"terminal_cpu": "cpu_percent", "terminal_memory": "memory_percent", "terminal_temperature": "soc_temperature_c"}[metric]
|
||||
}
|
||||
|
||||
func terminalAlertQuery(column string) string {
|
||||
return `SELECT t.id,t.name,false unavailable,m.sampled_at,
|
||||
CASE WHEN m.supported AND t.last_seen>now()-interval '90 seconds' AND m.sampled_at>now()-interval '90 seconds'
|
||||
AND m.sampled_at<=now() THEN m.` + column + ` ELSE NULL END value
|
||||
FROM terminals t LEFT JOIN terminal_metrics_current m ON m.terminal_id=t.id
|
||||
WHERE t.enabled AND t.token_hash IS NOT NULL AND t.status!='unregistered'`
|
||||
}
|
||||
|
||||
// Non-terminal metrics keep a null freshness flag for backward compatibility.
|
||||
// A value becomes unknown on missing/old samples, unsupported agents or revocation.
|
||||
const terminalAlertFreshSQL = `CASE WHEN metric IN ('terminal_cpu','terminal_memory','terminal_temperature') THEN EXISTS(
|
||||
SELECT 1 FROM terminals t JOIN terminal_metrics_current m ON m.terminal_id=t.id
|
||||
WHERE t.id=alerts.target_id AND t.enabled AND t.token_hash IS NOT NULL AND t.status!='unregistered'
|
||||
AND t.last_seen>now()-interval '90 seconds' AND m.supported AND m.sampled_at>now()-interval '90 seconds' AND m.sampled_at<=now()
|
||||
AND CASE alerts.metric WHEN 'terminal_cpu' THEN m.cpu_percent WHEN 'terminal_memory' THEN m.memory_percent
|
||||
WHEN 'terminal_temperature' THEN m.soc_temperature_c END IS NOT NULL) ELSE NULL END`
|
||||
|
||||
func evaluateTerminalHigh(ctx context.Context, tx *sqlx.Tx, rule alertRule, target observation, column string) error {
|
||||
// Count source time, not repeated evaluator ticks. A source gap over 90s or
|
||||
// an intervening null/normal history sample starts a new continuous segment.
|
||||
// The history range is at most 90 seconds in the non-gap case and uses its PK.
|
||||
_, err := tx.ExecContext(ctx, `INSERT INTO alert_states(rule_id,target_id,first_seen,last_sample_at) VALUES($1,$2,GREATEST($3::timestamptz,$5::timestamptz),$3)
|
||||
ON CONFLICT(rule_id,target_id) DO UPDATE SET first_seen=CASE
|
||||
WHEN alert_states.last_sample_at IS NULL OR EXCLUDED.last_sample_at-alert_states.last_sample_at>interval '90 seconds'
|
||||
OR EXISTS(SELECT 1 FROM terminal_metric_samples s WHERE s.terminal_id=$2
|
||||
AND s.sampled_at>GREATEST(alert_states.last_sample_at,EXCLUDED.last_sample_at-interval '90 seconds') AND s.sampled_at<=EXCLUDED.last_sample_at
|
||||
AND (s.`+column+` IS NULL OR s.`+column+`<$4)) THEN EXCLUDED.first_seen ELSE alert_states.first_seen END,
|
||||
last_sample_at=EXCLUDED.last_sample_at
|
||||
WHERE alert_states.last_sample_at IS NULL OR EXCLUDED.last_sample_at>alert_states.last_sample_at`, rule.ID, target.ID, target.SampledAt, rule.Threshold, rule.UpdatedAt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, `INSERT INTO alerts(id,rule_id,rule_name,metric,target_id,target_name,value,threshold,started_at)
|
||||
SELECT $1,$2,$3,$4,$5,$6,$7,$8,first_seen FROM alert_states WHERE rule_id=$2 AND target_id=$5
|
||||
AND ($9=0 OR last_sample_at-first_seen>=make_interval(secs=>$9) OR EXISTS(SELECT 1 FROM alerts WHERE rule_id=$2 AND target_id=$5 AND status='firing'))
|
||||
ON CONFLICT(rule_id,target_id) WHERE status='firing' DO UPDATE SET value=EXCLUDED.value`,
|
||||
store.ID("alert_"), rule.ID, rule.Name, rule.Metric, target.ID, target.Name, *target.Value, rule.Threshold, rule.HoldSeconds)
|
||||
return err
|
||||
}
|
||||
Reference in new issue
Block a user