| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- package cloudwatch
- import (
- "context"
- "errors"
- "time"
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/service/cloudwatch"
- "github.com/grafana/grafana/pkg/components/simplejson"
- "github.com/grafana/grafana/pkg/tsdb"
- )
- func (e *CloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
- result := &tsdb.Response{
- Results: make(map[string]*tsdb.QueryResult),
- }
- firstQuery := queryContext.Queries[0]
- queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: firstQuery.RefId}
- parameters := firstQuery.Model
- usePrefixMatch := parameters.Get("prefixMatching").MustBool(false)
- region := parameters.Get("region").MustString("")
- namespace := parameters.Get("namespace").MustString("")
- metricName := parameters.Get("metricName").MustString("")
- dimensions := parameters.Get("dimensions").MustMap()
- statistics, extendedStatistics, err := parseStatistics(parameters)
- if err != nil {
- return nil, err
- }
- period := int64(parameters.Get("period").MustInt(0))
- if period == 0 && !usePrefixMatch {
- period = 300
- }
- actionPrefix := parameters.Get("actionPrefix").MustString("")
- alarmNamePrefix := parameters.Get("alarmNamePrefix").MustString("")
- svc, err := e.getClient(region)
- if err != nil {
- return nil, err
- }
- var alarmNames []*string
- if usePrefixMatch {
- params := &cloudwatch.DescribeAlarmsInput{
- MaxRecords: aws.Int64(100),
- ActionPrefix: aws.String(actionPrefix),
- AlarmNamePrefix: aws.String(alarmNamePrefix),
- }
- resp, err := svc.DescribeAlarms(params)
- if err != nil {
- return nil, errors.New("Failed to call cloudwatch:DescribeAlarms")
- }
- alarmNames = filterAlarms(resp, namespace, metricName, dimensions, statistics, extendedStatistics, period)
- } else {
- if region == "" || namespace == "" || metricName == "" || len(statistics) == 0 {
- return result, nil
- }
- var qd []*cloudwatch.Dimension
- for k, v := range dimensions {
- if vv, ok := v.(string); ok {
- qd = append(qd, &cloudwatch.Dimension{
- Name: aws.String(k),
- Value: aws.String(vv),
- })
- }
- }
- for _, s := range statistics {
- params := &cloudwatch.DescribeAlarmsForMetricInput{
- Namespace: aws.String(namespace),
- MetricName: aws.String(metricName),
- Dimensions: qd,
- Statistic: aws.String(s),
- Period: aws.Int64(int64(period)),
- }
- resp, err := svc.DescribeAlarmsForMetric(params)
- if err != nil {
- return nil, errors.New("Failed to call cloudwatch:DescribeAlarmsForMetric")
- }
- for _, alarm := range resp.MetricAlarms {
- alarmNames = append(alarmNames, alarm.AlarmName)
- }
- }
- for _, s := range extendedStatistics {
- params := &cloudwatch.DescribeAlarmsForMetricInput{
- Namespace: aws.String(namespace),
- MetricName: aws.String(metricName),
- Dimensions: qd,
- ExtendedStatistic: aws.String(s),
- Period: aws.Int64(int64(period)),
- }
- resp, err := svc.DescribeAlarmsForMetric(params)
- if err != nil {
- return nil, errors.New("Failed to call cloudwatch:DescribeAlarmsForMetric")
- }
- for _, alarm := range resp.MetricAlarms {
- alarmNames = append(alarmNames, alarm.AlarmName)
- }
- }
- }
- startTime, err := queryContext.TimeRange.ParseFrom()
- if err != nil {
- return nil, err
- }
- endTime, err := queryContext.TimeRange.ParseTo()
- if err != nil {
- return nil, err
- }
- annotations := make([]map[string]string, 0)
- for _, alarmName := range alarmNames {
- params := &cloudwatch.DescribeAlarmHistoryInput{
- AlarmName: alarmName,
- StartDate: aws.Time(startTime),
- EndDate: aws.Time(endTime),
- MaxRecords: aws.Int64(100),
- }
- resp, err := svc.DescribeAlarmHistory(params)
- if err != nil {
- return nil, errors.New("Failed to call cloudwatch:DescribeAlarmHistory")
- }
- for _, history := range resp.AlarmHistoryItems {
- annotation := make(map[string]string)
- annotation["time"] = history.Timestamp.UTC().Format(time.RFC3339)
- annotation["title"] = *history.AlarmName
- annotation["tags"] = *history.HistoryItemType
- annotation["text"] = *history.HistorySummary
- annotations = append(annotations, annotation)
- }
- }
- transformAnnotationToTable(annotations, queryResult)
- result.Results[firstQuery.RefId] = queryResult
- return result, err
- }
- func transformAnnotationToTable(data []map[string]string, result *tsdb.QueryResult) {
- table := &tsdb.Table{
- Columns: make([]tsdb.TableColumn, 4),
- Rows: make([]tsdb.RowValues, 0),
- }
- table.Columns[0].Text = "time"
- table.Columns[1].Text = "title"
- table.Columns[2].Text = "tags"
- table.Columns[3].Text = "text"
- for _, r := range data {
- values := make([]interface{}, 4)
- values[0] = r["time"]
- values[1] = r["title"]
- values[2] = r["tags"]
- values[3] = r["text"]
- table.Rows = append(table.Rows, values)
- }
- result.Tables = append(result.Tables, table)
- result.Meta.Set("rowCount", len(data))
- }
- func filterAlarms(alarms *cloudwatch.DescribeAlarmsOutput, namespace string, metricName string, dimensions map[string]interface{}, statistics []string, extendedStatistics []string, period int64) []*string {
- alarmNames := make([]*string, 0)
- for _, alarm := range alarms.MetricAlarms {
- if namespace != "" && *alarm.Namespace != namespace {
- continue
- }
- if metricName != "" && *alarm.MetricName != metricName {
- continue
- }
- match := true
- if len(dimensions) == 0 {
- // all match
- } else if len(alarm.Dimensions) != len(dimensions) {
- match = false
- } else {
- for _, d := range alarm.Dimensions {
- if _, ok := dimensions[*d.Name]; !ok {
- match = false
- }
- }
- }
- if !match {
- continue
- }
- if len(statistics) != 0 {
- found := false
- for _, s := range statistics {
- if *alarm.Statistic == s {
- found = true
- }
- }
- if !found {
- continue
- }
- }
- if len(extendedStatistics) != 0 {
- found := false
- for _, s := range extendedStatistics {
- if *alarm.Statistic == s {
- found = true
- }
- }
- if !found {
- continue
- }
- }
- if period != 0 && *alarm.Period != period {
- continue
- }
- alarmNames = append(alarmNames, alarm.AlarmName)
- }
- return alarmNames
- }
|