From e8727897f088ffe79b6dfc250c53e50b3bcbb591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Wed, 5 Apr 2017 23:02:30 -0700 Subject: [PATCH] Use new alertmanager package methods for fetching AM data Change to using mapper module, remove old code --- alertmanager/alerts.go | 42 ---------------------- alertmanager/alerts_test.go | 30 ---------------- alertmanager/silences.go | 45 ----------------------- alertmanager/silences_test.go | 30 ---------------- timer.go | 67 ++++++++++++++--------------------- transform/jira.go | 2 +- transform/jira_test.go | 56 +++++++++++++++++++---------- 7 files changed, 64 insertions(+), 208 deletions(-) delete mode 100644 alertmanager/alerts.go delete mode 100644 alertmanager/alerts_test.go delete mode 100644 alertmanager/silences.go delete mode 100644 alertmanager/silences_test.go diff --git a/alertmanager/alerts.go b/alertmanager/alerts.go deleted file mode 100644 index e9772319e..000000000 --- a/alertmanager/alerts.go +++ /dev/null @@ -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 -} diff --git a/alertmanager/alerts_test.go b/alertmanager/alerts_test.go deleted file mode 100644 index fcc503d08..000000000 --- a/alertmanager/alerts_test.go +++ /dev/null @@ -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) - } -} diff --git a/alertmanager/silences.go b/alertmanager/silences.go deleted file mode 100644 index c12b51b01..000000000 --- a/alertmanager/silences.go +++ /dev/null @@ -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 -} diff --git a/alertmanager/silences_test.go b/alertmanager/silences_test.go deleted file mode 100644 index bbec9c433..000000000 --- a/alertmanager/silences_test.go +++ /dev/null @@ -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) - } -} diff --git a/timer.go b/timer.go index 65f052f85..3a4a9358f 100644 --- a/timer.go +++ b/timer.go @@ -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 != "" { diff --git a/transform/jira.go b/transform/jira.go index 2e608a156..e7a0302ac 100644 --- a/transform/jira.go +++ b/transform/jira.go @@ -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 != "" { diff --git a/transform/jira_test.go b/transform/jira_test.go index 10dff5b48..c74a54afb 100644 --- a/transform/jira_test.go +++ b/transform/jira_test.go @@ -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",