Use new alertmanager package methods for fetching AM data

Change to using mapper module, remove old code
This commit is contained in:
Łukasz Mierzwa
2017-04-05 23:02:30 -07:00
parent d02028e581
commit e8727897f0
7 changed files with 64 additions and 208 deletions

View File

@@ -1,42 +0,0 @@
package alertmanager
import (
"errors"
"time"
"github.com/cloudflare/unsee/config"
"github.com/cloudflare/unsee/models"
"github.com/cloudflare/unsee/transport"
log "github.com/Sirupsen/logrus"
)
// AlertGroupsAPIResponse is the schema of API response for /api/v1/alerts/groups
type AlertGroupsAPIResponse struct {
Status string `json:"status"`
Groups []models.AlertmanagerAlertGroup `json:"data"`
ErrorType string `json:"errorType"`
Error string `json:"error"`
}
// Get response from Alertmanager /api/v1/alerts/groups
func (response *AlertGroupsAPIResponse) Get() error {
start := time.Now()
url, err := transport.JoinURL(config.Config.AlertmanagerURI, "api/v1/alerts/groups")
if err != nil {
return err
}
err = transport.GetJSONFromURL(url, config.Config.AlertmanagerTimeout, response)
if err != nil {
return err
}
if response.Status != "success" {
return errors.New(response.Error)
}
log.Infof("Got %d alert group(s) in %s", len(response.Groups), time.Since(start))
return nil
}

View File

@@ -1,30 +0,0 @@
package alertmanager_test
import (
"io/ioutil"
"testing"
log "github.com/Sirupsen/logrus"
"github.com/cloudflare/unsee/alertmanager"
httpmock "gopkg.in/jarcoal/httpmock.v1"
)
func TestAlertGroupsAPIResponseGet(t *testing.T) {
log.SetOutput(ioutil.Discard) // disable logging to console
httpmock.Activate()
defer httpmock.DeactivateAndReset()
mockJSON, err := ioutil.ReadFile("../mock/api/v1/alerts/groups")
if err != nil {
t.Errorf("Can't open mock 'alerts/groups' file: %s", err.Error())
}
httpmock.RegisterResponder("GET", "api/v1/alerts/groups", httpmock.NewBytesResponder(200, mockJSON))
response := alertmanager.AlertGroupsAPIResponse{}
err = response.Get()
if err != nil {
t.Errorf("AlertGroupsAPIResponse.Get() failed: %s", err.Error())
}
if response.Status != "success" {
t.Errorf("Invalid AlertGroupsAPIResponse status: %s", response.Status)
}
}

View File

@@ -1,45 +0,0 @@
package alertmanager
import (
"errors"
"fmt"
"math"
"time"
"github.com/cloudflare/unsee/config"
"github.com/cloudflare/unsee/models"
"github.com/cloudflare/unsee/transport"
log "github.com/Sirupsen/logrus"
)
// SilenceAPIResponse is what Alertmanager API returns
type SilenceAPIResponse struct {
Status string `json:"status"`
Data []models.AlertmanagerSilence `json:"data"`
ErrorType string `json:"errorType"`
Error string `json:"error"`
}
// Get will return fresh data from Alertmanager API
func (response *SilenceAPIResponse) Get() error {
start := time.Now()
url, err := transport.JoinURL(config.Config.AlertmanagerURI, "api/v1/silences")
if err != nil {
return err
}
url = fmt.Sprintf("%s?limit=%d", url, math.MaxUint32)
err = transport.GetJSONFromURL(url, config.Config.AlertmanagerTimeout, response)
if err != nil {
return err
}
if response.Status != "success" {
return errors.New(response.Error)
}
log.Infof("Got %d silences(s) in %s", len(response.Data), time.Since(start))
return nil
}

View File

@@ -1,30 +0,0 @@
package alertmanager_test
import (
"io/ioutil"
"testing"
log "github.com/Sirupsen/logrus"
"github.com/cloudflare/unsee/alertmanager"
httpmock "gopkg.in/jarcoal/httpmock.v1"
)
func TestSilenceAPIResponseGet(t *testing.T) {
log.SetOutput(ioutil.Discard) // disable logging to console
httpmock.Activate()
defer httpmock.DeactivateAndReset()
mockJSON, err := ioutil.ReadFile("../mock/api/v1/silences")
if err != nil {
t.Errorf("Can't open mock 'silences' file: %s", err.Error())
}
httpmock.RegisterResponder("GET", "api/v1/silences", httpmock.NewBytesResponder(200, mockJSON))
response := alertmanager.SilenceAPIResponse{}
err = response.Get()
if err != nil {
t.Errorf("SilenceAPIResponse.Get() failed: %s", err.Error())
}
if response.Status != "success" {
t.Errorf("Invalid SilenceAPIResponse status: %s", response.Status)
}
}

View File

@@ -22,9 +22,9 @@ import (
// from Alertmanager API, it's called by Ticker timer
func PullFromAlertmanager() {
log.Info("Pulling latest alerts and silences from Alertmanager")
v := alertmanager.GetVersion()
silenceResponse := alertmanager.SilenceAPIResponse{}
err := silenceResponse.Get()
silences, err := alertmanager.GetSilences(v)
if err != nil {
log.Error(err.Error())
errorLock.Lock()
@@ -34,8 +34,7 @@ func PullFromAlertmanager() {
return
}
alertGroups := alertmanager.AlertGroupsAPIResponse{}
err = alertGroups.Get()
alertGroups, err := alertmanager.GetAlerts(v)
if err != nil {
log.Error(err.Error())
errorLock.Lock()
@@ -46,13 +45,9 @@ func PullFromAlertmanager() {
}
silenceStore := make(map[string]models.UnseeSilence)
for _, silence := range silenceResponse.Data {
jiraID, jiraLink := transform.DetectJIRAs(&silence)
silenceStore[silence.ID] = models.UnseeSilence{
AlertmanagerSilence: silence,
JiraID: jiraID,
JiraURL: jiraLink,
}
for _, silence := range silences {
silence.JiraID, silence.JiraURL = transform.DetectJIRAs(&silence)
silenceStore[silence.ID] = silence
}
store.Store.SetSilences(silenceStore)
@@ -66,20 +61,10 @@ func PullFromAlertmanager() {
var counterAlertsSilenced float64
var counterAlertsUnsilenced float64
for _, alertGroup := range alertGroups.Groups {
if len(alertGroup.Blocks) == 0 {
// skip groups with empty blocks
continue
}
for _, ag := range alertGroups {
// used to generate group content hash
agHasher := sha1.New()
ag := models.UnseeAlertGroup{
Labels: alertGroup.Labels,
Alerts: []models.UnseeAlert{},
}
alerts := map[string]models.UnseeAlert{}
ignoredLabels := []string{}
@@ -87,28 +72,28 @@ func PullFromAlertmanager() {
ignoredLabels = append(ignoredLabels, il)
}
for _, alertBlock := range alertGroup.Blocks {
for _, alert := range alertBlock.Alerts {
apiAlert := models.UnseeAlert{AlertmanagerAlert: alert}
apiAlert.Annotations, apiAlert.Links = transform.DetectLinks(apiAlert.Annotations)
apiAlert.Labels = transform.StripLables(ignoredLabels, apiAlert.Labels)
apiAlert.Fingerprint = fmt.Sprintf("%x", structhash.Sha1(apiAlert, 1))
// add alert to map if not yet present
if _, found := alerts[apiAlert.Fingerprint]; !found {
alerts[apiAlert.Fingerprint] = apiAlert
io.WriteString(agHasher, apiAlert.Fingerprint) // alert group hasher
}
for k, v := range alert.Labels {
transform.ColorLabel(colorStore, k, v)
}
for _, alert := range ag.Alerts {
// skip duplicated alerts
if _, found := alerts[alert.Fingerprint]; found {
continue
}
alert.Annotations, alert.Links = transform.DetectLinks(alert.Annotations)
alert.Labels = transform.StripLables(ignoredLabels, alert.Labels)
alert.Fingerprint = fmt.Sprintf("%x", structhash.Sha1(alert, 1))
alerts[alert.Fingerprint] = alert
io.WriteString(agHasher, alert.Fingerprint) // alert group hasher
for k, v := range alert.Labels {
transform.ColorLabel(colorStore, k, v)
}
}
// reset alerts, we need to deduplicate
ag.Alerts = []models.UnseeAlert{}
for _, alert := range alerts {
ag.Alerts = append(ag.Alerts, alert)
if alert.Silenced != "" {

View File

@@ -37,7 +37,7 @@ func ParseRules(rules []string) {
// DetectJIRAs will try to find JIRA links in Alertmanager silence objects
// using regexp rules from configuration that were parsed and populated
// by ParseRules call
func DetectJIRAs(silence *models.AlertmanagerSilence) (jiraID, jiraLink string) {
func DetectJIRAs(silence *models.UnseeSilence) (jiraID, jiraLink string) {
for _, jdr := range jiraDetectRules {
jiraID := jdr.Regexp.FindString(silence.Comment)
if jiraID != "" {

View File

@@ -8,7 +8,7 @@ import (
)
type jiraTest struct {
silence models.AlertmanagerSilence
silence models.UnseeSilence
jiraID string
jiraLink string
}
@@ -20,54 +20,72 @@ var jiraRules = []string{
var jiraTests = []jiraTest{
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "Lorem ipsum dolor sit amet",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "Lorem ipsum dolor sit amet",
},
},
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "DVOPS-123",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "DVOPS-123",
},
},
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "DEVOPS team",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "DEVOPS team",
},
},
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "a project-1 b",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "a project-1 b",
},
},
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "a PROJECT- b",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "a PROJECT- b",
},
},
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "DEVOPS-1",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "DEVOPS-1",
},
},
jiraID: "DEVOPS-1",
jiraLink: "https://jira.example.com/browse/DEVOPS-1",
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "DEVOPS-123",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "DEVOPS-123",
},
},
jiraID: "DEVOPS-123",
jiraLink: "https://jira.example.com/browse/DEVOPS-123",
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "a DEVOPS-1 b",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "a DEVOPS-1 b",
},
},
jiraID: "DEVOPS-1",
jiraLink: "https://jira.example.com/browse/DEVOPS-1",
},
jiraTest{
silence: models.AlertmanagerSilence{
Comment: "PROJECT-9",
silence: models.UnseeSilence{
AlertmanagerSilence: models.AlertmanagerSilence{
Comment: "PROJECT-9",
},
},
jiraID: "PROJECT-9",
jiraLink: "https://example.com/browse/PROJECT-9",