mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
cloudwatch: Add resource_arns template query function
Implements feature request #8207
This commit is contained in:
parent
6fb76b7c9b
commit
fa977ce090
@ -74,6 +74,12 @@ Here is a minimal policy example:
|
||||
"ec2:DescribeRegions"
|
||||
],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "AllowReadingResourcesForTags",
|
||||
"Effect" : "Allow",
|
||||
"Action" : "tag:GetResources",
|
||||
"Resource" : "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -128,6 +134,7 @@ Name | Description
|
||||
*dimension_values(region, namespace, metric, dimension_key, [filters])* | Returns a list of dimension values matching the specified `region`, `namespace`, `metric`, `dimension_key` or you can use dimension `filters` to get more specific result as well.
|
||||
*ebs_volume_ids(region, instance_id)* | Returns a list of volume ids matching the specified `region`, `instance_id`.
|
||||
*ec2_instance_attribute(region, attribute_name, filters)* | Returns a list of attributes matching the specified `region`, `attribute_name`, `filters`.
|
||||
*resource_arns(region, resource_type, tags)* | Returns a list of ARNs matching the specified `region`, `resource_type` and `tags`.
|
||||
|
||||
For details about the metrics CloudWatch provides, please refer to the [CloudWatch documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CW_Support_For_AWS.html).
|
||||
|
||||
@ -143,6 +150,8 @@ Query | Service
|
||||
*dimension_values(us-east-1,AWS/RDS,CPUUtilization,DBInstanceIdentifier)* | RDS
|
||||
*dimension_values(us-east-1,AWS/S3,BucketSizeBytes,BucketName)* | S3
|
||||
*dimension_values(us-east-1,CWAgent,disk_used_percent,device,{"InstanceId":"$instance_id"})* | CloudWatch Agent
|
||||
*resource_arns(eu-west-1,elasticloadbalancing:loadbalancer,{"elasticbeanstalk:environment-name":["myApp-dev","myApp-prod"]})* | ELB
|
||||
*resource_arns(eu-west-1,ec2:instance,{"elasticbeanstalk:environment-name":["myApp-dev","myApp-prod"]})* | EC2
|
||||
|
||||
## ec2_instance_attribute examples
|
||||
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi/resourcegroupstaggingapiiface"
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/metrics"
|
||||
@ -28,7 +29,8 @@ import (
|
||||
|
||||
type CloudWatchExecutor struct {
|
||||
*models.DataSource
|
||||
ec2Svc ec2iface.EC2API
|
||||
ec2Svc ec2iface.EC2API
|
||||
rgtaSvc resourcegroupstaggingapiiface.ResourceGroupsTaggingAPIAPI
|
||||
}
|
||||
|
||||
type DatasourceInfo struct {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/metrics"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
@ -200,6 +201,8 @@ func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryCo
|
||||
data, err = e.handleGetEbsVolumeIds(ctx, parameters, queryContext)
|
||||
case "ec2_instance_attribute":
|
||||
data, err = e.handleGetEc2InstanceAttribute(ctx, parameters, queryContext)
|
||||
case "resource_arns":
|
||||
data, err = e.handleGetResourceArns(ctx, parameters, queryContext)
|
||||
}
|
||||
|
||||
transformToTable(data, queryResult)
|
||||
@ -536,6 +539,65 @@ func (e *CloudWatchExecutor) handleGetEc2InstanceAttribute(ctx context.Context,
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *CloudWatchExecutor) ensureRGTAClientSession(region string) error {
|
||||
if e.rgtaSvc == nil {
|
||||
dsInfo := e.getDsInfo(region)
|
||||
cfg, err := e.getAwsConfig(dsInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to call ec2:getAwsConfig, %v", err)
|
||||
}
|
||||
sess, err := session.NewSession(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to call ec2:NewSession, %v", err)
|
||||
}
|
||||
e.rgtaSvc = resourcegroupstaggingapi.New(sess, cfg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *CloudWatchExecutor) handleGetResourceArns(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
|
||||
region := parameters.Get("region").MustString()
|
||||
resourceType := parameters.Get("resourceType").MustString()
|
||||
filterJson := parameters.Get("tags").MustMap()
|
||||
|
||||
err := e.ensureRGTAClientSession(region)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var filters []*resourcegroupstaggingapi.TagFilter
|
||||
for k, v := range filterJson {
|
||||
if vv, ok := v.([]interface{}); ok {
|
||||
var vvvvv []*string
|
||||
for _, vvv := range vv {
|
||||
if vvvv, ok := vvv.(string); ok {
|
||||
vvvvv = append(vvvvv, &vvvv)
|
||||
}
|
||||
}
|
||||
filters = append(filters, &resourcegroupstaggingapi.TagFilter{
|
||||
Key: aws.String(k),
|
||||
Values: vvvvv,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var resourceTypes []*string
|
||||
resourceTypes = append(resourceTypes, &resourceType)
|
||||
|
||||
resources, err := e.resourceGroupsGetResources(region, filters, resourceTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]suggestData, 0)
|
||||
for _, resource := range resources.ResourceTagMappingList {
|
||||
data := *resource.ResourceARN
|
||||
result = append(result, suggestData{Text: data, Value: data})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *CloudWatchExecutor) cloudwatchListMetrics(region string, namespace string, metricName string, dimensions []*cloudwatch.DimensionFilter) (*cloudwatch.ListMetricsOutput, error) {
|
||||
svc, err := e.getClient(region)
|
||||
if err != nil {
|
||||
@ -587,6 +649,28 @@ func (e *CloudWatchExecutor) ec2DescribeInstances(region string, filters []*ec2.
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *CloudWatchExecutor) resourceGroupsGetResources(region string, filters []*resourcegroupstaggingapi.TagFilter, resourceTypes []*string) (*resourcegroupstaggingapi.GetResourcesOutput, error) {
|
||||
params := &resourcegroupstaggingapi.GetResourcesInput{
|
||||
ResourceTypeFilters: resourceTypes,
|
||||
TagFilters: filters,
|
||||
}
|
||||
|
||||
var resp resourcegroupstaggingapi.GetResourcesOutput
|
||||
err := e.rgtaSvc.GetResourcesPages(params,
|
||||
func(page *resourcegroupstaggingapi.GetResourcesOutput, lastPage bool) bool {
|
||||
resources, _ := awsutil.ValuesAtPath(page, "ResourceTagMappingList")
|
||||
for _, resource := range resources {
|
||||
resp.ResourceTagMappingList = append(resp.ResourceTagMappingList, resource.(*resourcegroupstaggingapi.ResourceTagMapping))
|
||||
}
|
||||
return !lastPage
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.New("Failed to call tags:GetResources")
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func getAllMetrics(cwData *DatasourceInfo) (cloudwatch.ListMetricsOutput, error) {
|
||||
creds, err := GetCredentials(cwData)
|
||||
if err != nil {
|
||||
|
@ -232,6 +232,14 @@ export default class CloudWatchDatasource {
|
||||
});
|
||||
}
|
||||
|
||||
getResourceARNs(region, resourceType, tags) {
|
||||
return this.doMetricQueryRequest('resource_arns', {
|
||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||
resourceType: this.templateSrv.replace(resourceType),
|
||||
tags: tags,
|
||||
});
|
||||
}
|
||||
|
||||
metricFindQuery(query) {
|
||||
let region;
|
||||
let namespace;
|
||||
@ -293,6 +301,15 @@ export default class CloudWatchDatasource {
|
||||
return this.getEc2InstanceAttribute(region, targetAttributeName, filterJson);
|
||||
}
|
||||
|
||||
|
||||
const resourceARNsQuery = query.match(/^resource_arns\(([^,]+?),\s?([^,]+?),\s?(.+?)\)/);
|
||||
if (resourceARNsQuery) {
|
||||
region = resourceARNsQuery[1];
|
||||
const resourceType = resourceARNsQuery[2];
|
||||
const tagsJSON = JSON.parse(this.templateSrv.replace(resourceARNsQuery[3]));
|
||||
return this.getResourceARNs(region, resourceType, tagsJSON);
|
||||
}
|
||||
|
||||
return this.$q.when([]);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user