add level mappings

This allows to map the command exit codes to any other output level
which can then be reported by the notification plugin.
With the provided colors, the frontend will show them accordingly.
This commit is contained in:
Gibheer 2018-12-11 12:37:30 +01:00
parent c62916c46e
commit dece1ac2dc
3 changed files with 104 additions and 24 deletions

View File

@ -26,6 +26,29 @@ type (
DB string `json:"db"` DB string `json:"db"`
Listen string `json:"listen"` Listen string `json:"listen"`
} }
Context struct {
Mappings map[int]map[int]MapEntry
Checks []check
}
MapEntry struct {
Title string
Color string
}
check struct {
NodeName string
CommandName string
CheckID int64
MappingId int
State int
Notify bool
Enabled bool
Notice sql.NullString
NextTime time.Time
Msg string
}
) )
func main() { func main() {
@ -149,21 +172,10 @@ func showChecks(w http.ResponseWriter, r *http.Request) {
return return
} }
type check struct {
NodeName string
CommandName string
CheckID int64
State int
Notify bool
Enabled bool
Notice sql.NullString
NextTime time.Time
Msg string
}
checks := []check{} checks := []check{}
for rows.Next() { for rows.Next() {
c := check{} c := check{}
err := rows.Scan(&c.CheckID, &c.NodeName, &c.CommandName, &c.State, &c.Notify, &c.Enabled, &c.Notice, &c.NextTime, &c.Msg) err := rows.Scan(&c.CheckID, &c.NodeName, &c.CommandName, &c.MappingId, &c.State, &c.Notify, &c.Enabled, &c.Notice, &c.NextTime, &c.Msg)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("problems with the database")) w.Write([]byte("problems with the database"))
@ -181,8 +193,17 @@ func showChecks(w http.ResponseWriter, r *http.Request) {
log.Printf("could not parse template: %s", err) log.Printf("could not parse template: %s", err)
return return
} }
con := Context{
Checks: checks,
}
if err := loadMappings(&con); err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("problem with the mappings"))
log.Printf("could not load mappings: %s", err)
return
}
w.Header()["Content-Type"] = []string{"text/html"} w.Header()["Content-Type"] = []string{"text/html"}
if err := tmpl.Execute(w, checks); err != nil { if err := tmpl.Execute(w, con); err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("problem with a template")) w.Write([]byte("problem with a template"))
log.Printf("could not execute template: %s", err) log.Printf("could not execute template: %s", err)
@ -193,6 +214,7 @@ func showChecks(w http.ResponseWriter, r *http.Request) {
func showUnhandledHosts(w http.ResponseWriter, r *http.Request) { func showUnhandledHosts(w http.ResponseWriter, r *http.Request) {
} }
func showUnhandledGroups(w http.ResponseWriter, r *http.Request) { func showUnhandledGroups(w http.ResponseWriter, r *http.Request) {
rows, err := DB.Query(SQLShowUnhandledGroups) rows, err := DB.Query(SQLShowUnhandledGroups)
if err != nil { if err != nil {
@ -236,8 +258,40 @@ func showUnhandledGroups(w http.ResponseWriter, r *http.Request) {
return return
} }
func loadMappings(c *Context) error {
c.Mappings = map[int]map[int]MapEntry{}
rows, err := DB.Query(SQLShowMappings)
if err != nil {
return err
}
for rows.Next() {
if rows.Err() != nil {
return rows.Err()
}
var (
mapId int
target int
title string
color string
)
if err := rows.Scan(&mapId, &target, &title, &color); err != nil {
return err
}
ma, found := c.Mappings[mapId]
if !found {
ma = map[int]MapEntry{}
c.Mappings[mapId] = ma
}
ma[target] = MapEntry{Title: title, Color: color}
}
return nil
}
var ( var (
SQLShowChecks = `select c.id, n.name, co.name, ac.states[1] as state, ac.notify, SQLShowMappings = `select mapping_id, target, title, color
from mapping_level`
SQLShowChecks = `select c.id, n.name, co.name, ac.mapping_id, ac.states[1] as state, ac.notify,
ac.enabled, ac.notice, ac.next_time, ac.msg ac.enabled, ac.notice, ac.next_time, ac.msg
from active_checks ac from active_checks ac
join checks c on ac.check_id = c.id join checks c on ac.check_id = c.id
@ -280,10 +334,15 @@ var (
form nav { display: flex; flex-direction: column; } form nav { display: flex; flex-direction: column; }
form nav > * { margin: 0.5em; } form nav > * { margin: 0.5em; }
table td, table th { padding: 0.5em; } table td, table th { padding: 0.5em; }
td.state-0 { background: green; } {{ range $mapId, $mapping := .Mappings }}
{{ range $target, $val := $mapping }}
td.state-{{ $mapId }}-{{ $target }} { background: {{ $val.Color }}; }
{{ end }}
{{ end }}
/* td.state-0 { background: green; }
td.state-1 { background: orange; } td.state-1 { background: orange; }
td.state-2 { background: red; } td.state-2 { background: red; }
td.state-99 { background: gray; } td.state-99 { background: gray; } */
</style> </style>
</head> </head>
<body> <body>
@ -321,11 +380,12 @@ var (
<thead><tr><th></th><th>host</th><th>status</th><th>next check</th><th>message</th></tr></thead> <thead><tr><th></th><th>host</th><th>status</th><th>next check</th><th>message</th></tr></thead>
<tbody> <tbody>
{{ $current := "" }} {{ $current := "" }}
{{ range . }} {{ $mapping := .Mappings }}
{{ range .Checks }}
<tr> <tr>
<td><input type="checkbox" name="checks" value="{{ .CheckID }}" /></td> <td><input type="checkbox" name="checks" value="{{ .CheckID }}" /></td>
<td>{{ if ne $current .NodeName }}{{ $current = .NodeName }}{{ .NodeName }}{{ end }}</td> <td>{{ if ne $current .NodeName }}{{ $current = .NodeName }}{{ .NodeName }}{{ end }}</td>
<td class="state-{{ .State }}">{{ .CommandName }} - {{ .State }}</td> <td class="state-{{ .MappingId }}-{{ .State }}">{{ .CommandName }} - {{ (index $mapping .MappingId .State).Title }}</td>
<td>{{ .NextTime.Format "2006.01.02 15:04:05" }}</td> <td>{{ .NextTime.Format "2006.01.02 15:04:05" }}</td>
<td><pre>{{ .Msg }}</pre></td> <td><pre>{{ .Msg }}</pre></td>
</tr> </tr>

View File

@ -218,11 +218,13 @@ var (
where c.last_refresh < c.updated or c.last_refresh is null where c.last_refresh < c.updated or c.last_refresh is null
limit 1 limit 1
for update of c skip locked;` for update of c skip locked;`
SQLRefreshActiveCheck = `insert into active_checks(check_id, cmdline, intval, enabled, notify, msg) SQLRefreshActiveCheck = `insert into active_checks(check_id, cmdline, intval, enabled, notify, msg, mapping_id)
select id, $2, c.intval, c.enabled, c.notify, case when ac.msg is null then '' else ac.msg end from checks c select c.id, $2, c.intval, c.enabled, c.notify, case when ac.msg is null then '' else ac.msg end, case when c.mapping_id is not null then c.mapping_id when n.mapping_id is not null then n.mapping_id else 1 end
from checks c
left join active_checks ac on c.id = ac.check_id left join active_checks ac on c.id = ac.check_id
where id = $1 left join nodes n on c.node_id = n.id
where c.id = $1
on conflict(check_id) on conflict(check_id)
do update set cmdline = $2, intval = excluded.intval, enabled = excluded.enabled, notify = excluded.notify;` do update set cmdline = $2, intval = excluded.intval, enabled = excluded.enabled, notify = excluded.notify, mapping_id = excluded.mapping_id;`
SQLUpdateLastRefresh = `update checks set last_refresh = now() where id = $1;` SQLUpdateLastRefresh = `update checks set last_refresh = now() where id = $1;`
) )

View File

@ -1,3 +1,18 @@
create table public.mappings(
id serial primary key,
name text not null,
description text not null
);
create table public.mapping_level(
mapping_id integer not null,
source int not null,
target int not null,
title text not null,
color text not null,
unique(mapping_id, source)
);
CREATE TABLE public.notifier ( CREATE TABLE public.notifier (
id serial NOT NULL primary key, id serial NOT NULL primary key,
name text NOT NULL name text NOT NULL
@ -10,10 +25,11 @@ CREATE TABLE public.groups (
CREATE TABLE public.nodes ( CREATE TABLE public.nodes (
id bigserial NOT NULL primary key, id bigserial NOT NULL primary key,
mapping_id int references mappings(id),
name text NOT NULL, name text NOT NULL,
updated timestamp with time zone DEFAULT now() NOT NULL, updated timestamp with time zone DEFAULT now() NOT NULL,
created timestamp with time zone DEFAULT now() NOT NULL, created timestamp with time zone DEFAULT now() NOT NULL,
message text NOT NULL message text NOT NULL,
); );
CREATE TABLE public.nodes_groups ( CREATE TABLE public.nodes_groups (
@ -28,13 +44,14 @@ CREATE TABLE public.commands (
command text NOT NULL, command text NOT NULL,
updated timestamp with time zone DEFAULT now() NOT NULL, updated timestamp with time zone DEFAULT now() NOT NULL,
created timestamp with time zone DEFAULT now() NOT NULL, created timestamp with time zone DEFAULT now() NOT NULL,
message text NOT NULL message text NOT NULL,
); );
CREATE TABLE public.checks ( CREATE TABLE public.checks (
id bigserial NOT NULL primary key, id bigserial NOT NULL primary key,
node_id integer not null references nodes(id) on delete cascade, node_id integer not null references nodes(id) on delete cascade,
command_id integer not null references commands(id) on delete restrict, command_id integer not null references commands(id) on delete restrict,
mapping_id int references mappings(id),
intval interval DEFAULT '00:05:00'::interval NOT NULL, intval interval DEFAULT '00:05:00'::interval NOT NULL,
options jsonb DEFAULT '{}'::jsonb NOT NULL, options jsonb DEFAULT '{}'::jsonb NOT NULL,
updated timestamp with time zone DEFAULT now() NOT NULL, updated timestamp with time zone DEFAULT now() NOT NULL,
@ -48,6 +65,7 @@ CREATE TABLE public.checks (
CREATE TABLE public.active_checks ( CREATE TABLE public.active_checks (
check_id bigint NOT NULL references checks(id) on delete cascade, check_id bigint NOT NULL references checks(id) on delete cascade,
mapping_id int not null references mappings(id),
cmdline text[] NOT NULL, cmdline text[] NOT NULL,
next_time timestamp with time zone DEFAULT now() NOT NULL, next_time timestamp with time zone DEFAULT now() NOT NULL,
states integer[] DEFAULT ARRAY[0] NOT NULL, states integer[] DEFAULT ARRAY[0] NOT NULL,