monzero/cmd/monfront/checks.go

226 lines
6.6 KiB
Go

package main
import (
"database/sql"
"net/http"
"time"
"github.com/lib/pq"
)
type (
check struct {
NodeId int
NodeName string
CommandName string
CheckID int64
CheckName string
MappingId int
State int
Enabled bool
Notify bool
Notice sql.NullString
NextTime time.Time
Msg string
StateSince time.Time
}
checkDetails struct {
Id int64
Name string
Message string
Enabled bool
Updated time.Time
LastRefresh time.Time
NextTime time.Time
MappingId int
MappingName string
NodeId int
NodeName string
NodeMessage string
CommandId int
CommandName string
CommandLine []string
CommandMessage string
States []int64
Notice sql.NullString
Notifiers []notifier
Notifications []notification
CheckerID int
CheckerName string
CheckerMsg string
}
notifier struct {
Id int
Name string
Enabled bool
}
notification struct {
Id int64
State int
Output string
Inserted time.Time
Sent pq.NullTime
NotifierName string
MappingId int
}
)
// showCheck loads shows the notifications for a specific check.
func showCheck(con *Context) {
cd := checkDetails{}
con.CheckDetails = &cd
id, found := con.r.URL.Query()["check_id"]
if !found {
con.Error = "no check given to view"
returnError(http.StatusNotFound, con, con.w)
return
}
query := `select c.id, c.name, c.message, c.enabled, c.updated, c.last_refresh,
m.id, m.name, n.id, n.name, n.message, co.id, co.Name, co.message,
ac.cmdline, ac.states, ac.msg, ac.next_time, ch.id, ch.name, ch.description
from checks c
join active_checks ac on c.id = ac.check_id
join nodes n on c.node_id = n.id
join commands co on c.command_id = co.id
join mappings m on ac.mapping_id = m.id
join checkers ch on c.checker_id = ch.id
where c.id = $1::bigint`
err := DB.QueryRow(query, id[0]).Scan(&cd.Id, &cd.Name, &cd.Message, &cd.Enabled,
&cd.Updated, &cd.LastRefresh, &cd.MappingId, &cd.MappingName, &cd.NodeId,
&cd.NodeName, &cd.NodeMessage, &cd.CommandId, &cd.CommandName, &cd.CommandMessage,
pq.Array(&cd.CommandLine), pq.Array(&cd.States), &cd.Notice, &cd.NextTime,
&cd.CheckerID, &cd.CheckerName, &cd.CheckerMsg)
if err != nil && err == sql.ErrNoRows {
con.w.Header()["Location"] = []string{"/"}
con.w.WriteHeader(http.StatusSeeOther)
return
} else if err != nil {
con.w.WriteHeader(http.StatusInternalServerError)
con.w.Write([]byte("problems with the database"))
con.log.Info("could not get check details for check id", "id", id[0], "error", err)
return
}
query = `select n.id, states[1], output, inserted, sent, no.name, n.mapping_id
from notifications n
join notifier no on n.notifier_id = no.id
where check_id = $1::bigint
order by inserted desc
limit 500`
rows, err := DB.Query(query, cd.Id)
defer rows.Close()
if err != nil {
con.log.Info("could not load notifications", "error", err)
con.Error = "could not load notification information"
returnError(http.StatusInternalServerError, con, con.w)
return
}
cd.Notifications = []notification{}
for rows.Next() {
if err := rows.Err(); err != nil {
con.log.Info("could not load notifications", "error", err)
con.Error = "could not load notification information"
returnError(http.StatusInternalServerError, con, con.w)
return
}
no := notification{}
if err := rows.Scan(&no.Id, &no.State, &no.Output, &no.Inserted,
&no.Sent, &no.NotifierName, &no.MappingId); err != nil {
con.log.Info("could not scan notifications", "error", err)
con.Error = "could not load notification information"
returnError(http.StatusInternalServerError, con, con.w)
return
}
cd.Notifications = append(cd.Notifications, no)
}
if err := con.loadMappings(); err != nil {
con.w.WriteHeader(http.StatusInternalServerError)
con.w.Write([]byte("problem with the mappings"))
con.log.Info("could not load mappings", "error", err)
return
}
con.w.Header()["Content-Type"] = []string{"text/html"}
con.Render("check")
}
func showChecks(con *Context) {
query := `select c.id, c.name, n.id, n.name, co.name, ac.mapping_id, ac.states[1] as state,
ac.enabled, ac.notice, ac.next_time, ac.msg,
case when cn.check_id is null then false else true end as notify_enabled,
state_since
from active_checks ac
join checks c on ac.check_id = c.id
join nodes n on c.node_id = n.id
join commands co on c.command_id = co.id
left join ( select distinct check_id from checks_notify where enabled = true) cn on c.id = cn.check_id`
filter := newFilter()
con.Filter = filter
if id, found := con.r.URL.Query()["group_id"]; found {
query += ` join nodes_groups ng on n.id = ng.node_id`
filter.Add("ng.group_id", "=", id[0], "int")
}
filter.filterChecks(con)
if search, found := con.r.URL.Query()["search"]; found {
filter.AddSpecial(
`to_tsvector('english', regexp_replace(n.name, '[.-/]', ' ', 'g'))`,
`@@`,
`to_tsquery('english', regexp_replace($%d, '[.-/]', ' & ', 'g') || ':*')`,
search[0])
}
if id, found := con.r.URL.Query()["node_id"]; found {
filter.Add("n.id", "=", id[0], "int")
}
if id, found := con.r.URL.Query()["check_id"]; found {
filter.Add("c.id", "=", id[0], "int")
}
where, params := filter.Join()
if len(where) > 0 {
query += " where " + where
}
query += ` order by n.name, c.name, co.name`
rows, err := DB.Query(query, params...)
if err != nil {
con.w.WriteHeader(http.StatusInternalServerError)
con.w.Write([]byte("problems with the database"))
con.log.Info("could not get check list", "error", err)
return
}
defer rows.Close()
checks := []check{}
for rows.Next() {
c := check{}
err := rows.Scan(&c.CheckID, &c.CheckName, &c.NodeId, &c.NodeName, &c.CommandName, &c.MappingId,
&c.State, &c.Enabled, &c.Notice, &c.NextTime, &c.Msg, &c.Notify, &c.StateSince)
if err != nil {
con.w.WriteHeader(http.StatusInternalServerError)
returnError(http.StatusInternalServerError, con, con.w)
con.log.Info("could not get check list", "error", err)
return
}
checks = append(checks, c)
}
con.Checks = checks
if err := con.loadCommands(); err != nil {
con.Error = "could not load commands"
returnError(http.StatusInternalServerError, con, con.w)
con.log.Info("could not get commands", "error", err)
return
}
if err := con.loadMappings(); err != nil {
con.Error = "could not load mapping data"
con.w.WriteHeader(http.StatusInternalServerError)
con.w.Write([]byte("problem with the mappings"))
con.log.Info("could not load mappings", "error", err)
return
}
con.w.Header()["Content-Type"] = []string{"text/html"}
con.Render("checklist")
return
}