9ce6153bd8
Wire up monitor detail view in TUI with type-specific icons. Add SQLite WAL glob to gitignore. Extend store interface with bulk-fetch and history queries for the detail panel.
152 lines
6.0 KiB
Go
152 lines
6.0 KiB
Go
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
"log"
|
|
|
|
_ "github.com/lib/pq"
|
|
)
|
|
|
|
type PostgresDialect struct{}
|
|
|
|
func NewPostgresStore(connStr string) (*SQLStore, error) {
|
|
return NewSQLStore("postgres", connStr, &PostgresDialect{})
|
|
}
|
|
|
|
func (d *PostgresDialect) DriverName() string { return "postgres" }
|
|
func (d *PostgresDialect) BoolFalse() string { return "FALSE" }
|
|
|
|
func (d *PostgresDialect) CreateTablesSQL() []string {
|
|
return []string{
|
|
`CREATE TABLE IF NOT EXISTS alerts (
|
|
id SERIAL PRIMARY KEY,
|
|
name TEXT, type TEXT, settings TEXT
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS sites (
|
|
id SERIAL PRIMARY KEY,
|
|
name TEXT DEFAULT 'New Monitor', url TEXT, type TEXT DEFAULT 'http',
|
|
token TEXT, interval INTEGER, alert_id INTEGER,
|
|
check_ssl BOOLEAN DEFAULT FALSE, threshold INTEGER DEFAULT 7,
|
|
max_retries INTEGER DEFAULT 0, hostname TEXT DEFAULT '',
|
|
port INTEGER DEFAULT 0, timeout INTEGER DEFAULT 0,
|
|
method TEXT DEFAULT 'GET', description TEXT DEFAULT '',
|
|
parent_id INTEGER DEFAULT 0, accepted_codes TEXT DEFAULT '200-299',
|
|
dns_resolve_type TEXT DEFAULT '', dns_server TEXT DEFAULT '',
|
|
ignore_tls BOOLEAN DEFAULT FALSE, paused BOOLEAN DEFAULT FALSE
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS users (
|
|
id SERIAL PRIMARY KEY,
|
|
username TEXT NOT NULL, public_key TEXT NOT NULL,
|
|
role TEXT DEFAULT 'user'
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS check_history (
|
|
id SERIAL PRIMARY KEY,
|
|
site_id INTEGER NOT NULL, latency_ns BIGINT,
|
|
is_up BOOLEAN, checked_at TIMESTAMP DEFAULT NOW()
|
|
)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_check_history_site ON check_history(site_id, checked_at DESC)`,
|
|
`CREATE TABLE IF NOT EXISTS nodes (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
region TEXT DEFAULT '',
|
|
last_seen TIMESTAMP DEFAULT NOW(),
|
|
version TEXT DEFAULT ''
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS logs (
|
|
id SERIAL PRIMARY KEY,
|
|
message TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS maintenance_windows (
|
|
id SERIAL PRIMARY KEY,
|
|
monitor_id INTEGER DEFAULT 0,
|
|
title TEXT NOT NULL,
|
|
description TEXT DEFAULT '',
|
|
type TEXT DEFAULT 'maintenance',
|
|
start_time TIMESTAMP NOT NULL,
|
|
end_time TIMESTAMP,
|
|
created_by TEXT DEFAULT '',
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS preferences (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT NOT NULL
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS state_changes (
|
|
id SERIAL PRIMARY KEY,
|
|
site_id INTEGER NOT NULL,
|
|
from_status TEXT NOT NULL,
|
|
to_status TEXT NOT NULL,
|
|
error_reason TEXT DEFAULT '',
|
|
changed_at TIMESTAMP DEFAULT NOW()
|
|
)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_state_changes_site ON state_changes(site_id, changed_at DESC)`,
|
|
`CREATE TABLE IF NOT EXISTS alert_health (
|
|
alert_id INTEGER PRIMARY KEY,
|
|
last_send_at TIMESTAMP,
|
|
last_send_ok BOOLEAN DEFAULT FALSE,
|
|
last_error TEXT DEFAULT '',
|
|
send_count INTEGER DEFAULT 0,
|
|
fail_count INTEGER DEFAULT 0
|
|
)`,
|
|
}
|
|
}
|
|
|
|
func (d *PostgresDialect) MigrationsSQL() []string {
|
|
return []string{
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS hostname TEXT DEFAULT ''",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS port INTEGER DEFAULT 0",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS timeout INTEGER DEFAULT 0",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS method TEXT DEFAULT 'GET'",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS description TEXT DEFAULT ''",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS parent_id INTEGER DEFAULT 0",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS accepted_codes TEXT DEFAULT '200-299'",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns_resolve_type TEXT DEFAULT ''",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns_server TEXT DEFAULT ''",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS ignore_tls BOOLEAN DEFAULT FALSE",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS paused BOOLEAN DEFAULT FALSE",
|
|
"ALTER TABLE check_history ADD COLUMN IF NOT EXISTS node_id TEXT DEFAULT ''",
|
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS regions TEXT DEFAULT ''",
|
|
}
|
|
}
|
|
|
|
func (d *PostgresDialect) UpsertNodeSQL() string {
|
|
return "INSERT INTO nodes (id, name, region, last_seen, version) VALUES ($1, $2, $3, NOW(), $4) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, region = EXCLUDED.region, last_seen = NOW(), version = EXCLUDED.version"
|
|
}
|
|
|
|
func (d *PostgresDialect) UpsertAlertHealthSQL() string {
|
|
return "INSERT INTO alert_health (alert_id, last_send_at, last_send_ok, last_error, send_count, fail_count) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (alert_id) DO UPDATE SET last_send_at = EXCLUDED.last_send_at, last_send_ok = EXCLUDED.last_send_ok, last_error = EXCLUDED.last_error, send_count = EXCLUDED.send_count, fail_count = EXCLUDED.fail_count"
|
|
}
|
|
|
|
func (d *PostgresDialect) ResetSequenceOnEmpty(db *sql.DB, table string) {}
|
|
|
|
func (d *PostgresDialect) ImportWipe(tx *sql.Tx) {
|
|
if _, err := tx.Exec("TRUNCATE TABLE sites RESTART IDENTITY CASCADE"); err != nil {
|
|
log.Printf("import wipe error: %v", err)
|
|
}
|
|
if _, err := tx.Exec("TRUNCATE TABLE alerts RESTART IDENTITY CASCADE"); err != nil {
|
|
log.Printf("import wipe error: %v", err)
|
|
}
|
|
if _, err := tx.Exec("TRUNCATE TABLE users RESTART IDENTITY CASCADE"); err != nil {
|
|
log.Printf("import wipe error: %v", err)
|
|
}
|
|
if _, err := tx.Exec("TRUNCATE TABLE maintenance_windows RESTART IDENTITY CASCADE"); err != nil {
|
|
log.Printf("import wipe error: %v", err)
|
|
}
|
|
}
|
|
|
|
func (d *PostgresDialect) ImportResetSequences(tx *sql.Tx) {
|
|
if _, err := tx.Exec("SELECT setval('sites_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sites))"); err != nil {
|
|
log.Printf("sequence reset error: %v", err)
|
|
}
|
|
if _, err := tx.Exec("SELECT setval('alerts_id_seq', (SELECT COALESCE(MAX(id), 1) FROM alerts))"); err != nil {
|
|
log.Printf("sequence reset error: %v", err)
|
|
}
|
|
if _, err := tx.Exec("SELECT setval('users_id_seq', (SELECT COALESCE(MAX(id), 1) FROM users))"); err != nil {
|
|
log.Printf("sequence reset error: %v", err)
|
|
}
|
|
if _, err := tx.Exec("SELECT setval('maintenance_windows_id_seq', (SELECT COALESCE(MAX(id), 1) FROM maintenance_windows))"); err != nil {
|
|
log.Printf("sequence reset error: %v", err)
|
|
}
|
|
}
|