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 }