feat(monitors): validate metric monitors and confine selectors to token scope
This commit is contained in:
@@ -118,6 +118,25 @@ func buildMonitor(args map[string]any) (models.Monitor, error) {
|
||||
if b, ok := rawTarget["insecure"].(bool); ok {
|
||||
target.Insecure = b
|
||||
}
|
||||
target.Metric = stringArg(rawTarget, "metric")
|
||||
target.Mount = stringArg(rawTarget, "mount")
|
||||
if n, ok := rawTarget["threshold"].(float64); ok {
|
||||
target.Threshold = n
|
||||
}
|
||||
if n, ok := rawTarget["period_sec"].(float64); ok {
|
||||
target.PeriodSec = int(n)
|
||||
}
|
||||
if n, ok := rawTarget["grace_sec"].(float64); ok {
|
||||
target.GraceSec = int(n)
|
||||
}
|
||||
if sel, ok := rawTarget["selector"].(map[string]any); ok {
|
||||
target.Selector = map[string]string{}
|
||||
for k, v := range sel {
|
||||
if s, ok := v.(string); ok {
|
||||
target.Selector[k] = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch monitorType {
|
||||
case models.MonitorHTTP, models.MonitorTLS:
|
||||
@@ -131,6 +150,9 @@ func buildMonitor(args map[string]any) (models.Monitor, error) {
|
||||
if monitorType == models.MonitorTCP && target.Port == 0 {
|
||||
return models.Monitor{}, fmt.Errorf("target.port is required for a tcp monitor")
|
||||
}
|
||||
case models.MonitorHeartbeat, models.MonitorMetric:
|
||||
// Full validation (validateHeartbeat / validateMetric) runs inside
|
||||
// services.CreateMonitor; nothing further is required here.
|
||||
default:
|
||||
return models.Monitor{}, fmt.Errorf("unknown monitor type %q", monitorType)
|
||||
}
|
||||
@@ -150,6 +172,10 @@ func buildMonitor(args map[string]any) (models.Monitor, error) {
|
||||
if n, ok := args["interval_sec"].(float64); ok && int(n) > 0 {
|
||||
interval = int(n)
|
||||
}
|
||||
forSec := 0
|
||||
if n, ok := args["for_sec"].(float64); ok && int(n) > 0 {
|
||||
forSec = int(n)
|
||||
}
|
||||
|
||||
return models.Monitor{
|
||||
Name: name,
|
||||
@@ -157,6 +183,7 @@ func buildMonitor(args map[string]any) (models.Monitor, error) {
|
||||
Type: monitorType,
|
||||
Target: target,
|
||||
IntervalSec: interval,
|
||||
ForSec: forSec,
|
||||
// Never armed on creation. A monitor that started enabled would begin
|
||||
// alerting real people the moment a model invented it, and creating
|
||||
// must stay a separate decision from acting.
|
||||
@@ -257,10 +284,11 @@ func init() {
|
||||
Name: "create_monitor",
|
||||
Args: []ToolArg{
|
||||
{Name: "name", Type: ArgString, Description: "Name for the monitor.", Required: true},
|
||||
{Name: "type", Type: ArgString, Description: "Check type: http, tcp, icmp or tls.", Required: true},
|
||||
{Name: "target", Type: ArgObject, Description: "What to check. http/tls take url; tcp/icmp take host, and tcp also port. Optional: method, keyword, expected_status, tls_warn_days, insecure.", Required: true},
|
||||
{Name: "type", Type: ArgString, Description: "Check type: http, tcp, icmp, tls, heartbeat or metric.", Required: true},
|
||||
{Name: "target", Type: ArgObject, Description: "What to check. http/tls take url; tcp/icmp take host, and tcp also port. Optional: method, keyword, expected_status, tls_warn_days, insecure. heartbeat takes period_sec and optional grace_sec; metric takes metric (disk_pct, disk_free_gb, mem_pct, load_per_core, unit_failed, container_unhealthy, reboot_pending_days, agent_offline_min), threshold, optional mount and selector (tag map).", Required: true},
|
||||
{Name: "group", Type: ArgString, Description: "Optional group name to file the monitor under."},
|
||||
{Name: "interval_sec", Type: ArgInteger, Description: "Seconds between checks; defaults to 60."},
|
||||
{Name: "for_sec", Type: ArgInteger, Description: "For a metric monitor, how long the condition must hold before a server counts as down."},
|
||||
},
|
||||
Write: true,
|
||||
Scope: "monitors:write",
|
||||
@@ -277,12 +305,17 @@ func init() {
|
||||
return nil, fmt.Errorf("could not create the monitor: %w", err)
|
||||
}
|
||||
LogCreated(c, "monitor", created.MonitorID, created.Name)
|
||||
return map[string]any{
|
||||
out := map[string]any{
|
||||
"monitor_id": created.MonitorID,
|
||||
"name": created.Name,
|
||||
"enabled": false,
|
||||
"note": "Created disabled. Enable it in Vantage to start checking.",
|
||||
}, nil
|
||||
}
|
||||
if created.HeartbeatToken != "" {
|
||||
out["heartbeat_token"] = created.HeartbeatToken
|
||||
out["heartbeat_token_note"] = "Shown once."
|
||||
}
|
||||
return out, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user