grafana/pkg/tsdb/cloudwatch/annotation_query.go

201 lines
5.6 KiB
Go
Raw Normal View History

2017-09-25 04:16:40 -05:00
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/plugins"
"github.com/grafana/grafana/pkg/util/errutil"
2017-09-25 04:16:40 -05:00
)
func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryContext plugins.DataQuery) (
plugins.DataResponse, error) {
result := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
2017-09-25 04:16:40 -05:00
}
firstQuery := queryContext.Queries[0]
queryResult := plugins.DataQueryResult{Meta: simplejson.New(), RefID: firstQuery.RefID}
2017-09-25 04:16:40 -05:00
parameters := firstQuery.Model
2017-09-26 01:45:52 -05:00
usePrefixMatch := parameters.Get("prefixMatching").MustBool(false)
2017-09-25 04:16:40 -05:00
region := parameters.Get("region").MustString("")
namespace := parameters.Get("namespace").MustString("")
metricName := parameters.Get("metricName").MustString("")
dimensions := parameters.Get("dimensions").MustMap()
statistics, err := parseStatistics(parameters)
if err != nil {
return plugins.DataResponse{}, err
}
2017-09-26 01:45:52 -05:00
period := int64(parameters.Get("period").MustInt(0))
if period == 0 && !usePrefixMatch {
period = 300
2017-09-25 04:16:40 -05:00
}
actionPrefix := parameters.Get("actionPrefix").MustString("")
alarmNamePrefix := parameters.Get("alarmNamePrefix").MustString("")
cli, err := e.getCWClient(region)
2017-09-25 04:16:40 -05:00
if err != nil {
return plugins.DataResponse{}, err
2017-09-25 04:16:40 -05:00
}
var alarmNames []*string
if usePrefixMatch {
params := &cloudwatch.DescribeAlarmsInput{
MaxRecords: aws.Int64(100),
ActionPrefix: aws.String(actionPrefix),
AlarmNamePrefix: aws.String(alarmNamePrefix),
}
resp, err := cli.DescribeAlarms(params)
2017-09-25 04:16:40 -05:00
if err != nil {
return plugins.DataResponse{}, errutil.Wrap("failed to call cloudwatch:DescribeAlarms", err)
2017-09-25 04:16:40 -05:00
}
alarmNames = filterAlarms(resp, namespace, metricName, dimensions, statistics, period)
2017-09-25 04:16:40 -05:00
} else {
if region == "" || namespace == "" || metricName == "" || len(statistics) == 0 {
return result, errors.New("invalid annotations query")
2017-09-25 04:16:40 -05:00
}
var qd []*cloudwatch.Dimension
for k, v := range dimensions {
if vv, ok := v.([]interface{}); ok {
for _, vvv := range vv {
if vvvv, ok := vvv.(string); ok {
qd = append(qd, &cloudwatch.Dimension{
Name: aws.String(k),
Value: aws.String(vvvv),
})
}
}
2017-09-25 04:16:40 -05:00
}
}
for _, s := range statistics {
params := &cloudwatch.DescribeAlarmsForMetricInput{
Namespace: aws.String(namespace),
MetricName: aws.String(metricName),
Dimensions: qd,
Statistic: aws.String(s),
2018-04-16 13:04:58 -05:00
Period: aws.Int64(period),
2017-09-25 04:16:40 -05:00
}
resp, err := cli.DescribeAlarmsForMetric(params)
2017-09-25 04:16:40 -05:00
if err != nil {
return plugins.DataResponse{}, errutil.Wrap("failed to call cloudwatch:DescribeAlarmsForMetric", err)
2017-09-25 04:16:40 -05:00
}
for _, alarm := range resp.MetricAlarms {
alarmNames = append(alarmNames, alarm.AlarmName)
}
}
}
startTime, err := queryContext.TimeRange.ParseFrom()
if err != nil {
return plugins.DataResponse{}, err
2017-09-25 04:16:40 -05:00
}
endTime, err := queryContext.TimeRange.ParseTo()
if err != nil {
return plugins.DataResponse{}, err
2017-09-25 04:16:40 -05:00
}
annotations := make([]map[string]string, 0)
for _, alarmName := range alarmNames {
params := &cloudwatch.DescribeAlarmHistoryInput{
2017-09-26 10:00:38 -05:00
AlarmName: alarmName,
StartDate: aws.Time(startTime),
EndDate: aws.Time(endTime),
MaxRecords: aws.Int64(100),
2017-09-25 04:16:40 -05:00
}
resp, err := cli.DescribeAlarmHistory(params)
2017-09-25 04:16:40 -05:00
if err != nil {
return plugins.DataResponse{}, errutil.Wrap("failed to call cloudwatch:DescribeAlarmHistory", err)
2017-09-25 04:16:40 -05:00
}
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, nil
2017-09-25 04:16:40 -05:00
}
func transformAnnotationToTable(data []map[string]string, result *plugins.DataQueryResult) {
table := plugins.DataTable{
Columns: make([]plugins.DataTableColumn, 4),
Rows: make([]plugins.DataRowValues, 0),
2017-09-25 04:16:40 -05:00
}
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, period int64) []*string {
2017-09-25 04:16:40 -05:00
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 {
if len(alarm.Dimensions) != len(dimensions) {
match = false
} else {
for _, d := range alarm.Dimensions {
if _, ok := dimensions[*d.Name]; !ok {
match = false
}
2017-09-26 01:45:52 -05:00
}
2017-09-25 04:16:40 -05:00
}
}
if !match {
continue
}
if len(statistics) != 0 {
found := false
for _, s := range statistics {
if *alarm.Statistic == s {
found = true
break
2017-09-25 04:16:40 -05:00
}
}
if !found {
continue
}
}
2017-09-26 01:45:52 -05:00
if period != 0 && *alarm.Period != period {
continue
}
2017-09-25 04:16:40 -05:00
alarmNames = append(alarmNames, alarm.AlarmName)
}
return alarmNames
}