Просмотр исходного кода

re-implement ec2_instance_attribute()

Mitsuhiro Tanda 8 лет назад
Родитель
Сommit
8fba6dcb0d

+ 73 - 0
pkg/tsdb/cloudwatch/metric_find_query.go

@@ -3,6 +3,7 @@ package cloudwatch
 import (
 	"context"
 	"errors"
+	"reflect"
 	"sort"
 	"strings"
 	"sync"
@@ -178,6 +179,9 @@ func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queries
 	case "ebs_volume_ids":
 		data, err = e.handleGetEbsVolumeIds(ctx, parameters, queryContext)
 		break
+	case "ec2_instance_attribute":
+		data, err = e.handleGetEc2InstanceAttribute(ctx, parameters, queryContext)
+		break
 	}
 	if err != nil {
 		queryResult.Error = err
@@ -342,6 +346,75 @@ func (e *CloudWatchExecutor) handleGetEbsVolumeIds(ctx context.Context, paramete
 	return result, nil
 }
 
+func (e *CloudWatchExecutor) handleGetEc2InstanceAttribute(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.QueryContext) ([]suggestData, error) {
+	region := parameters.Get("region").MustString()
+	attributeName := parameters.Get("attributeName").MustString()
+	filterJson := parameters.Get("filters").MustMap()
+
+	var filters []*ec2.Filter
+	for k, v := range filterJson {
+		if vv, ok := v.([]string); ok {
+			var vvvv []*string
+			for _, vvv := range vv {
+				vvvv = append(vvvv, &vvv)
+			}
+			filters = append(filters, &ec2.Filter{
+				Name:   aws.String(k),
+				Values: vvvv,
+			})
+		}
+	}
+
+	instances, err := e.ec2DescribeInstances(region, filters, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	result := make([]suggestData, 0)
+	dupCheck := make(map[string]bool)
+	for _, instance := range instances.Reservations[0].Instances {
+		tags := make(map[string]string)
+		for _, tag := range instance.Tags {
+			tags[*tag.Key] = *tag.Value
+		}
+
+		var data string
+		if strings.Index(attributeName, "Tags.") == 0 {
+			tagName := attributeName[5:]
+			data = tags[tagName]
+		} else {
+			attributePath := strings.Split(attributeName, ".")
+			v := reflect.ValueOf(instance)
+			for _, key := range attributePath {
+				if v.Kind() == reflect.Ptr {
+					v = v.Elem()
+				}
+				if v.Kind() != reflect.Struct {
+					return nil, errors.New("invalid attribute path")
+				}
+				v = v.FieldByName(key)
+			}
+			if attr, ok := v.Interface().(*string); ok {
+				data = *attr
+			} else {
+				return nil, errors.New("invalid attribute path")
+			}
+		}
+
+		if _, exists := dupCheck[data]; exists {
+			continue
+		}
+		dupCheck[data] = true
+		result = append(result, suggestData{Text: data, Value: data})
+	}
+
+	sort.Slice(result, func(i, j int) bool {
+		return result[i].Text < result[j].Text
+	})
+
+	return result, nil
+}
+
 func getAwsConfig(dsInfo *cwapi.DatasourceInfo) (*aws.Config, error) {
 	creds, err := cwapi.GetCredentials(dsInfo)
 	if err != nil {

+ 25 - 32
public/app/plugins/datasource/cloudwatch/datasource.js

@@ -270,6 +270,29 @@ function (angular, _, moment, dateMath, kbn, templatingVariable, CloudWatchAnnot
       }).then(function (r) { return transformSuggestDataFromTable(r); });
     };
 
+    this.getEc2InstanceAttribute = function(region, attributeName, filters) {
+      var range = timeSrv.timeRange();
+      return backendSrv.post('/api/tsdb/query', {
+        from: range.from,
+        to: range.to,
+        queries: [
+          {
+            refId: 'metricFindQuery',
+            intervalMs: 1, // dummy
+            maxDataPoints: 1, // dummy
+            datasourceId: this.instanceSettings.id,
+            type: 'metricFindQuery',
+            subtype: 'ec2_instance_attribute',
+            parameters: {
+              region: region,
+              attributeName: attributeName,
+              filters: filters
+            }
+          }
+        ]
+      }).then(function (r) { return transformSuggestDataFromTable(r); });
+    };
+
     this.performEC2DescribeInstances = function(region, filters, instanceIds) {
       return this.awsRequest({
         region: region,
@@ -283,12 +306,6 @@ function (angular, _, moment, dateMath, kbn, templatingVariable, CloudWatchAnnot
       var namespace;
       var metricName;
 
-      var transformSuggestData = function(suggestData) {
-        return _.map(suggestData, function(v) {
-          return { text: v };
-        });
-      };
-
       var regionQuery = query.match(/^regions\(\)/);
       if (regionQuery) {
         return this.getRegions();
@@ -329,33 +346,9 @@ function (angular, _, moment, dateMath, kbn, templatingVariable, CloudWatchAnnot
       var ec2InstanceAttributeQuery = query.match(/^ec2_instance_attribute\(([^,]+?),\s?([^,]+?),\s?(.+?)\)/);
       if (ec2InstanceAttributeQuery) {
         region = templateSrv.replace(ec2InstanceAttributeQuery[1]);
-        var filterJson = JSON.parse(templateSrv.replace(ec2InstanceAttributeQuery[3]));
-        var filters = _.map(filterJson, function(values, name) {
-          return {
-            Name: name,
-            Values: values
-          };
-        });
         var targetAttributeName = templateSrv.replace(ec2InstanceAttributeQuery[2]);
-
-        return this.performEC2DescribeInstances(region, filters, null).then(function(result) {
-          var attributes = _.chain(result.Reservations)
-          .map(function(reservations) {
-            return _.map(reservations.Instances, function(instance) {
-              var tags = {};
-              _.each(instance.Tags, function(tag) {
-                tags[tag.Key] = tag.Value;
-              });
-              instance.Tags = tags;
-              return instance;
-            });
-          })
-          .map(function(instances) {
-            return _.map(instances, targetAttributeName);
-          })
-          .flatten().uniq().sortBy().value();
-          return transformSuggestData(attributes);
-        });
+        var filterJson = JSON.parse(templateSrv.replace(ec2InstanceAttributeQuery[3]));
+        return this.getEc2InstanceAttribute(region, targetAttributeName, filterJson);
       }
 
       return $q.when([]);