You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
4.8 KiB
203 lines
4.8 KiB
package main |
|
|
|
import ( |
|
"fmt" |
|
"log" |
|
"github.com/bytemine/go-icinga2/event" |
|
. "g.hazardous.org/fkr/rotochute/rt2" |
|
) |
|
|
|
type actionFunc func(*ticketUpdater, *event.Notification) error |
|
|
|
// condition describes the properties an event must have to match. |
|
type condition struct { |
|
state event.State |
|
oldState event.State |
|
owned bool |
|
} |
|
|
|
// mapping describes how an event matching condition should be acted upon. |
|
type mapping struct { |
|
condition condition |
|
action actionFunc |
|
} |
|
|
|
type ticketUpdater struct { |
|
cache *cache |
|
rtClient rtClient |
|
mappings []mapping |
|
nobody string |
|
queue string |
|
closedStatus []string |
|
} |
|
|
|
func newTicketUpdater(cache *cache, rtClient rtClient, mappings []mapping, nobody string, queue string, closedStatus []string) *ticketUpdater { |
|
return &ticketUpdater{cache: cache, rtClient: rtClient, mappings: mappings, nobody: nobody, queue: queue, closedStatus: closedStatus} |
|
} |
|
|
|
func (t *ticketUpdater) update(e *event.Notification) error { |
|
if *debug { |
|
log.Printf("%x ticket updater: new event: %v", eventID(e), formatEventSubject(e)) |
|
} |
|
|
|
// get a possible old event and ticket from the cache |
|
oldEvent, ticketID, err := t.cache.getEventTicket(e) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
// assume a fresh event |
|
owned := false |
|
oldState := event.State(event.StateNil) |
|
|
|
// use switch here so we can use break |
|
switch { |
|
case oldEvent != nil && ticketID != -1: // existing event found |
|
oldTicket, err := t.rtClient.Ticket(ticketID) |
|
if err != nil { |
|
if *debug { |
|
log.Printf("%x ticket updater: ticket #%v in cache doesn't exist", eventID(e), ticketID) |
|
} |
|
break |
|
} |
|
|
|
// we have an old event |
|
oldState = oldEvent.CheckResult.State |
|
owned = oldTicket.Owner.ID != t.nobody |
|
|
|
// check if the ticket has a status which signals "closed". |
|
// if it is closed, we have no old status and the ticket is unowned. |
|
for _, v := range t.closedStatus { |
|
if oldTicket.Status == v { |
|
oldState = event.State(event.StateNil) |
|
owned = false |
|
if *debug { |
|
log.Printf("%x ticket updater: ticket #%v has closed status: %v", eventID(e), ticketID, oldTicket.Status) |
|
} |
|
} |
|
} |
|
} |
|
|
|
if *debug { |
|
log.Printf("%x ticket updater: ticket #%v owned: %v", eventID(e), ticketID, owned) |
|
} |
|
|
|
for _, v := range t.mappings { |
|
x := condition{ |
|
state: e.CheckResult.State, |
|
oldState: oldState, |
|
owned: owned, |
|
} |
|
|
|
if *debug { |
|
log.Printf("%x ticket updater: matching condition: %+v\tevent: %+v", eventID(e), v.condition, x) |
|
} |
|
|
|
if v.condition == x { |
|
if *debug { |
|
log.Printf("%x ticket updater: matched %+v", eventID(e), v.condition) |
|
} |
|
|
|
err := v.action(t, e) |
|
return err |
|
} |
|
} |
|
|
|
if *debug { |
|
log.Printf("%x ticket updater: no condition matched", eventID(e)) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (t *ticketUpdater) delete(e *event.Notification) error { |
|
_, ticketID, err := t.cache.getEventTicket(e) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
newTicket := &Ticket{ID: ticketID, Status: "deleted"} |
|
|
|
updatedTicket, err := t.rtClient.UpdateTicket(newTicket) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
if *debug { |
|
log.Printf("%x ticket updater: deleted ticket #%v", eventID(e), updatedTicket.ID) |
|
} |
|
|
|
if err = t.cache.deleteEventTicket(e); err != nil { |
|
return err |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func formatEventSubject(e *event.Notification) string { |
|
switch { |
|
case e.Host != "" && e.Service != "": |
|
return fmt.Sprintf("Host: %v Service: %v is %v", e.Host, e.Service, e.CheckResult.State.String()) |
|
case e.Host != "" && e.Service == "": |
|
return fmt.Sprintf("Host: %v is %v", e.Host, e.CheckResult.State.String()) |
|
default: |
|
return fmt.Sprintf("Host: %v Service: %v is %v", e.Host, e.Service, e.CheckResult.State.String()) |
|
} |
|
} |
|
|
|
func formatEventComment(e *event.Notification) string { |
|
if e.CheckResult.Output != "" { |
|
return fmt.Sprintf("New status: %v Output: %v", e.CheckResult.State.String(), e.CheckResult.Output) |
|
} |
|
|
|
return e.CheckResult.State.String() |
|
} |
|
|
|
func (t *ticketUpdater) comment(e *event.Notification) error { |
|
_, ticketID, err := t.cache.getEventTicket(e) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
err = t.rtClient.CommentTicket(ticketID, formatEventComment(e)) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
if *debug { |
|
log.Printf("%x ticket updater: commented ticket #%v", eventID(e), ticketID) |
|
} |
|
|
|
err = t.cache.updateEventTicket(e, ticketID) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (t *ticketUpdater) create(e *event.Notification) error { |
|
|
|
newTicket, err := t.rtClient.NewTicket(formatEventSubject(e), t.queue, fmt.Sprintf("Output: %s", e.CheckResult.Output)) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
if *debug { |
|
log.Printf("%x ticket updater: created ticket #%v", eventID(e), newTicket) |
|
} |
|
|
|
err = t.cache.updateEventTicket(e, newTicket) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (t *ticketUpdater) ignore(e *event.Notification) error { |
|
if *debug { |
|
log.Printf("%x ticket updater: ignoring event #%v", eventID(e), formatEventSubject(e)) |
|
} |
|
return nil |
|
}
|
|
|