func (s *Schedule) action(user, message string, t models.ActionType, st *models.IncidentState) (ak models.AlertKey, e error) { if err := collect.Add("actions", opentsdb.TagSet{"user": user, "alert": st.AlertKey.Name(), "type": t.String()}, 1); err != nil { slog.Errorln(err) } defer func() { if e == nil { if err := collect.Add("actions", opentsdb.TagSet{"user": user, "alert": st.AlertKey.Name(), "type": t.String()}, 1); err != nil { slog.Errorln(err) } if err := s.DataAccess.Notifications().ClearNotifications(st.AlertKey); err != nil { e = err } } }() isUnknown := st.LastAbnormalStatus == models.StUnknown timestamp := utcNow() switch t { case models.ActionAcknowledge: if !st.NeedAck { return "", fmt.Errorf("alert already acknowledged") } if !st.Open { return "", fmt.Errorf("cannot acknowledge closed alert") } st.NeedAck = false case models.ActionClose: if st.IsActive() { return "", fmt.Errorf("cannot close active alert") } fallthrough case models.ActionForceClose: st.Open = false st.End = ×tamp case models.ActionForget: if !isUnknown { return "", fmt.Errorf("can only forget unknowns") } fallthrough case models.ActionPurge: return st.AlertKey, s.DataAccess.State().Forget(st.AlertKey) case models.ActionNote: // pass default: return "", fmt.Errorf("unknown action type: %v", t) } st.Actions = append(st.Actions, models.Action{ Message: message, Time: timestamp, Type: t, User: user, }) _, err := s.DataAccess.State().UpdateIncidentState(st) return st.AlertKey, err }
func (s *Schedule) Action(user, message string, t models.ActionType, ak models.AlertKey) error { if err := collect.Add("actions", opentsdb.TagSet{"user": user, "alert": ak.Name(), "type": t.String()}, 1); err != nil { slog.Errorln(err) } st, err := s.DataAccess.State().GetLatestIncident(ak) if err != nil { return err } if st == nil { return fmt.Errorf("no such alert key: %v", ak) } ack := func() { delete(s.Notifications, ak) st.NeedAck = false } isUnknown := st.LastAbnormalStatus == models.StUnknown timestamp := time.Now().UTC() switch t { case models.ActionAcknowledge: if !st.NeedAck { return fmt.Errorf("alert already acknowledged") } if !st.Open { return fmt.Errorf("cannot acknowledge closed alert") } ack() case models.ActionClose: if st.NeedAck { ack() } if st.IsActive() { return fmt.Errorf("cannot close active alert") } st.Open = false st.End = ×tamp case models.ActionForget: if !isUnknown { return fmt.Errorf("can only forget unknowns") } return s.DataAccess.State().Forget(ak) default: return fmt.Errorf("unknown action type: %v", t) } // Would like to also track the alert group, but I believe this is impossible because any character // that could be used as a delimiter could also be a valid tag key or tag value character if err := collect.Add("actions", opentsdb.TagSet{"user": user, "alert": ak.Name(), "type": t.String()}, 1); err != nil { slog.Errorln(err) } st.Actions = append(st.Actions, models.Action{ Message: message, Time: timestamp, Type: t, User: user, }) return s.DataAccess.State().UpdateIncidentState(st) }