...

Source file src/edge-infra.dev/pkg/lib/gcp/monitoring/alerting/incidents.go

Documentation: edge-infra.dev/pkg/lib/gcp/monitoring/alerting

     1  package alerting
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  )
     8  
     9  // latest version that we care about
    10  const currVersion string = "1.2"
    11  
    12  // VersionCheck only exists to check version of message before parsing
    13  type VersionCheck struct {
    14  	Version string `json:"version"`
    15  }
    16  
    17  // IncidentWrapper is a wrapper for an Incident
    18  type IncidentWrapper struct {
    19  	Incident Incident `json:"incident"`
    20  	Version  string   `json:"version"`
    21  }
    22  
    23  // Incident is ...
    24  type Incident struct {
    25  	Condition               json.RawMessage   `json:"condition"`
    26  	ConditionName           string            `json:"condition_name"`
    27  	Documentation           Documentation     `json:"documentation"`
    28  	EndedAt                 *int              `json:"ended_at"`
    29  	ID                      string            `json:"incident_id"`
    30  	Metadata                Metadata          `json:"metadata"`
    31  	Metric                  Metric            `json:"metric"`
    32  	PolicyName              string            `json:"policy_name"`
    33  	PolicyUserLabels        map[string]string `json:"policy_user_labels"`
    34  	Resource                Resource          `json:"resource"`
    35  	ResourceID              string            `json:"resource_id"`
    36  	ResourceName            string            `json:"resource_name"`
    37  	ResourceTypeDisplayName string            `json:"resource_type_display_name"`
    38  	ScopingProjectID        string            `json:"scoping_project_id"`
    39  	ScopingProjectNumber    int               `json:"scoping_project_number"`
    40  	StartedAt               *int              `json:"started_at"`
    41  	State                   string            `json:"state"`
    42  	Summary                 string            `json:"summary"`
    43  	URL                     string            `json:"url"`
    44  }
    45  
    46  type MetricCondition struct {
    47  	MQL         MQL    `json:"conditionMonitoringQueryLanguage"`
    48  	DisplayName string `json:"displayName"`
    49  	Name        string `json:"name"`
    50  }
    51  
    52  type MQL struct {
    53  	Duration string  `json:"duration"`
    54  	Query    string  `json:"query"`
    55  	Trigger  Trigger `json:"trigger"` // todo - more verification, very few have this
    56  }
    57  
    58  type Trigger struct {
    59  	Count int `json:"count"`
    60  }
    61  
    62  type LogCondition struct {
    63  	MatchedLog  MatchedLog `json:"conditionMatchedLog"`
    64  	DisplayName string     `json:"displayName"`
    65  	Name        string     `json:""`
    66  }
    67  
    68  type MatchedLog struct {
    69  	Filter string `json:"filter"`
    70  }
    71  
    72  type Documentation struct {
    73  	Content  string `json:"content"`
    74  	MimeType string `json:"mime_type"`
    75  }
    76  
    77  type Metadata struct {
    78  	SystemLabels map[string]string `json:"system_labels"`
    79  	UserLabels   map[string]string `json:"user_labels"`
    80  }
    81  
    82  type Metric struct {
    83  	DisplayName string            `json:"displayName"`
    84  	Labels      map[string]string `json:"labels"`
    85  	Type        string            `json:"type"`
    86  }
    87  
    88  type Resource struct {
    89  	Labels map[string]string `json:"labels"`
    90  	Type   string            `json:"type"`
    91  }
    92  
    93  func Unmarshal(data []byte) (*IncidentWrapper, error) {
    94  	check := &VersionCheck{}
    95  	if err := json.Unmarshal(data, check); err != nil {
    96  		return nil, err
    97  	}
    98  	// todo - how to skip test message without throwing errors
    99  	// can probably just get them acked manually as we shouldn't get many of them
   100  	// only get sent when manually clicking a button in the gcp console
   101  	if check.Version != currVersion {
   102  		// ideally would like to log the msg json to make it easier to add
   103  		// for now rely on caller to make that decision
   104  		return nil, fmt.Errorf("incident message version '%s' unsupported", check.Version)
   105  	}
   106  
   107  	wrapper := &IncidentWrapper{}
   108  	if err := json.Unmarshal(data, wrapper); err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	// todo - not erroring as expected .... need to force an error
   113  	metricCond := &MetricCondition{}
   114  	if err := json.Unmarshal(wrapper.Incident.Condition, metricCond); err != nil {
   115  		logCond := &LogCondition{}
   116  		if logErr := json.Unmarshal(wrapper.Incident.Condition, logCond); logErr != nil {
   117  			return nil, logErr
   118  		}
   119  		return nil, err
   120  	}
   121  
   122  	return wrapper, nil
   123  }
   124  
   125  // Marshall is a custom implementation of json.Marshall because of the known implementation detail
   126  // https://cs.opensource.google/go/go/+/refs/tags/go1.17:src/encoding/json/encode.go;l=161. Incident
   127  // messages contain the full query used to generate the incident.
   128  func Marshall(inc *IncidentWrapper) ([]byte, error) {
   129  	buf := &bytes.Buffer{}
   130  	encoder := json.NewEncoder(buf)
   131  	encoder.SetEscapeHTML(false)
   132  	err := encoder.Encode(inc)
   133  	return buf.Bytes(), err
   134  }
   135  

View as plain text