github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/alertmanager/merger/v1_alerts.go (about)

     1  package merger
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"sort"
     7  
     8  	v1 "github.com/prometheus/alertmanager/api/v1"
     9  )
    10  
    11  const (
    12  	statusSuccess = "success"
    13  )
    14  
    15  // V1Alerts implements the Merger interface for GET /v1/alerts. It returns the union of alerts over
    16  // all the responses. When the same alert exists in multiple responses, the alert instance in the
    17  // earliest response is returned in the final response. We cannot use the UpdatedAt timestamp as
    18  // for V2Alerts, because the v1 API does not provide it.
    19  type V1Alerts struct{}
    20  
    21  func (V1Alerts) MergeResponses(in [][]byte) ([]byte, error) {
    22  	type bodyType struct {
    23  		Status string      `json:"status"`
    24  		Data   []*v1.Alert `json:"data"`
    25  	}
    26  
    27  	alerts := make([]*v1.Alert, 0)
    28  	for _, body := range in {
    29  		parsed := bodyType{}
    30  		if err := json.Unmarshal(body, &parsed); err != nil {
    31  			return nil, err
    32  		}
    33  		if parsed.Status != statusSuccess {
    34  			return nil, fmt.Errorf("unable to merge response of status: %s", parsed.Status)
    35  		}
    36  		alerts = append(alerts, parsed.Data...)
    37  	}
    38  
    39  	merged, err := mergeV1Alerts(alerts)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	body := bodyType{
    44  		Status: statusSuccess,
    45  		Data:   merged,
    46  	}
    47  
    48  	return json.Marshal(body)
    49  }
    50  
    51  func mergeV1Alerts(in []*v1.Alert) ([]*v1.Alert, error) {
    52  	// Select an arbitrary alert for each distinct alert.
    53  	alerts := make(map[string]*v1.Alert)
    54  	for _, alert := range in {
    55  		key := alert.Fingerprint
    56  		if _, ok := alerts[key]; !ok {
    57  			alerts[key] = alert
    58  		}
    59  	}
    60  
    61  	result := make([]*v1.Alert, 0, len(alerts))
    62  	for _, alert := range alerts {
    63  		result = append(result, alert)
    64  	}
    65  
    66  	// Mimic Alertmanager which returns alerts ordered by fingerprint (as string).
    67  	sort.Slice(result, func(i, j int) bool {
    68  		return result[i].Fingerprint < result[j].Fingerprint
    69  	})
    70  
    71  	return result, nil
    72  }