Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add table aws_iot_fleet_metric Closes #1994 #2000

Merged
merged 17 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aws/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
"aws_inspector_exclusion": tableAwsInspectorExclusion(ctx),
"aws_inspector_finding": tableAwsInspectorFinding(ctx),
"aws_iot_thing": tableAwsIoTThing(ctx),
"aws_iot_fleet_metric": tableAwsIoTFleetMetric(ctx),
"aws_kinesis_consumer": tableAwsKinesisConsumer(ctx),
"aws_kinesis_firehose_delivery_stream": tableAwsKinesisFirehoseDeliveryStream(ctx),
"aws_kinesis_stream": tableAwsKinesisStream(ctx),
Expand Down
299 changes: 299 additions & 0 deletions aws/table_aws_iot_fleet_metric.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
package aws

import (
"context"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/iot"
"github.com/aws/aws-sdk-go-v2/service/iot/types"

iotv1 "github.com/aws/aws-sdk-go/service/iot"

"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
)

//// TABLE DEFINITION

func tableAwsIoTFleetMetric(_ context.Context) *plugin.Table {
return &plugin.Table{
Name: "aws_iot_fleet_metric",
Description: "AWS IoT Fleet Metric",
Get: &plugin.GetConfig{
KeyColumns: plugin.SingleColumn("metric_name"),
Hydrate: getIoTFleetMetric,
Tags: map[string]string{"service": "iot", "action": "DescribeFleetMetric"},
IgnoreConfig: &plugin.IgnoreConfig{
ShouldIgnoreErrorFunc: shouldIgnoreErrors([]string{"ResourceNotFoundException"}),
},
},
List: &plugin.ListConfig{
Hydrate: listIoTFleetMetrics,
Tags: map[string]string{"service": "iot", "action": "ListFleetMetrics"},
},
HydrateConfig: []plugin.HydrateConfig{
{
Func: getIoTFleetMetric,
Tags: map[string]string{"service": "iot", "action": "DescribeFleetMetric"},
},
{
Func: getIoTFleetMetricTags,
Tags: map[string]string{"service": "iot", "action": "ListTagsForResource"},
},
},
GetMatrixItemFunc: SupportedRegionMatrix(iotv1.EndpointsID),
Columns: awsRegionalColumns([]*plugin.Column{
{
Name: "metric_name",
Description: "The name of the fleet metric to describe.",
Type: proto.ColumnType_STRING,
},
{
Name: "arn",
Description: "The ARN of the fleet metric to describe.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("MetricArn"),
},
{
Name: "index_name",
Description: "The name of the index to search.",
Type: proto.ColumnType_STRING,
Hydrate: getIoTFleetMetric,
},
{
Name: "description",
Description: "The fleet metric description.",
Type: proto.ColumnType_STRING,
Hydrate: getIoTFleetMetric,
},
{
Name: "creation_date",
Description: "The date when the fleet metric is created.",
Type: proto.ColumnType_TIMESTAMP,
Hydrate: getIoTFleetMetric,
Transform: transform.FromField("CreationDate"),
},
{
Name: "last_modified_date",
Description: "The date when the fleet metric is last modified.",
Type: proto.ColumnType_TIMESTAMP,
Hydrate: getIoTFleetMetric,
},
{
Name: "aggregation_field",
Description: "The field to aggregate.",
Type: proto.ColumnType_STRING,
Hydrate: getIoTFleetMetric,
},
{
Name: "aggregation_type_name",
Description: "The name of the aggregation type.",
Type: proto.ColumnType_STRING,
Hydrate: getIoTFleetMetric,
Transform: transform.FromField("AggregationType.Name"),
},
{
Name: "period",
Description: "The time in seconds between fleet metric emissions. Range [60(1 min), 86400(1 day)] and must be multiple of 60.",
Type: proto.ColumnType_INT,
Hydrate: getIoTFleetMetric,
},
{
Name: "query_string",
Description: "The search query string.",
Type: proto.ColumnType_STRING,
Hydrate: getIoTFleetMetric,
},
{
Name: "query_version",
Description: "The search query version.",
Type: proto.ColumnType_STRING,
Hydrate: getIoTFleetMetric,
},
{
Name: "unit",
Description: "Used to support unit transformation such as milliseconds to seconds. The unit must be supported by CW metric (https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html)",
Type: proto.ColumnType_STRING,
Hydrate: getIoTFleetMetric,
},
{
Name: "version",
Description: "The version of the fleet metric.",
Type: proto.ColumnType_INT,
Hydrate: getIoTFleetMetric,
},
{
Name: "aggregation_type_values",
Description: "A list of the values of aggregation types.",
Type: proto.ColumnType_JSON,
Hydrate: getIoTFleetMetric,
Transform: transform.FromField("AggregationType.Values"),
},
{
Name: "tags_src",
Description: "A list of tags currently associated with the thing type.",
Type: proto.ColumnType_JSON,
Hydrate: getIoTFleetMetricTags,
Transform: transform.FromField("Tags"),
},

// Steampipe standard columns
{
Name: "title",
Description: resourceInterfaceDescription("title"),
Type: proto.ColumnType_STRING,
Transform: transform.FromField("MetricName"),
},
{
Name: "tags",
Description: resourceInterfaceDescription("tags"),
Type: proto.ColumnType_JSON,
Hydrate: getIoTFleetMetricTags,
Transform: transform.From(iotFleetMetricTagListToTagsMap),
},
{
Name: "akas",
Description: resourceInterfaceDescription("akas"),
Type: proto.ColumnType_JSON,
Transform: transform.FromField("MetricArn").Transform(transform.EnsureStringArray),
},
}),
}
}

//// LIST FUNCTION

func listIoTFleetMetrics(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
// Create Session
svc, err := IoTClient(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("aws_iot_fleet_metric.listIoTFleetMetrics", "connection_error", err)
return nil, err
}
if svc == nil {
// Unsupported region, return no data
return nil, nil
}

// Limiting the results
maxLimit := int32(250)
if d.QueryContext.Limit != nil {
limit := int32(*d.QueryContext.Limit)
if limit < maxLimit {
maxLimit = limit
}
}

input := &iot.ListFleetMetricsInput{
MaxResults: aws.Int32(maxLimit),
}

paginator := iot.NewListFleetMetricsPaginator(svc, input, func(o *iot.ListFleetMetricsPaginatorOptions) {
o.Limit = maxLimit
o.StopOnDuplicateToken = true
})

// List call
for paginator.HasMorePages() {
// apply rate limiting
d.WaitForListRateLimit(ctx)

output, err := paginator.NextPage(ctx)
if err != nil {
plugin.Logger(ctx).Error("aws_iot_fleet_metric.listIoTFleetMetrics", "api_error", err)
return nil, err
}

for _, item := range output.FleetMetrics {
d.StreamListItem(ctx, item)

// Context can be cancelled due to manual cancellation or the limit has been hit
if d.RowsRemaining(ctx) == 0 {
return nil, nil
}
}
}

return nil, err
}

//// HYDRATE FUNCTIONS

func getIoTFleetMetric(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
metricName := ""
if h.Item != nil {
t := h.Item.(types.FleetMetricNameAndArn)
metricName = *t.MetricName
} else {
metricName = d.EqualsQualString("metric_name")
}

if metricName == "" {
return nil, nil
}

// Create service
svc, err := IoTClient(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("aws_iot_fleet_metric.getIoTFleetMetric", "connection_error", err)
return nil, err
}

params := &iot.DescribeFleetMetricInput{
MetricName: aws.String(metricName),
}

resp, err := svc.DescribeFleetMetric(ctx, params)
if err != nil {
plugin.Logger(ctx).Error("aws_iot_fleet_metric.getIoTFleetMetric", "api_error", err)
return nil, err
}

return resp, nil
}

func getIoTFleetMetricTags(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
typeArn := ""
switch item := h.Item.(type) {
case *iot.DescribeThingTypeOutput:
typeArn = *item.ThingTypeArn
case types.ThingTypeDefinition:
typeArn = *item.ThingTypeArn
}

// Create service
svc, err := IoTClient(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("aws_iot_fleet_metric.getIoTFleetMetricTags", "connection_error", err)
return nil, err
}

params := &iot.ListTagsForResourceInput{
ResourceArn: aws.String(typeArn),
}

endpointTags, err := svc.ListTagsForResource(ctx, params)
if err != nil {
plugin.Logger(ctx).Error("aws_iot_fleet_metric.getIoTFleetMetricTags", "api_error", err)
return nil, err
}

return endpointTags, nil
}

//// TRANSFORM FUNCTIONS

func iotFleetMetricTagListToTagsMap(_ context.Context, d *transform.TransformData) (interface{}, error) {
data := d.HydrateItem.(*iot.ListTagsForResourceOutput)

// Mapping the resource tags inside turbotTags
if data.Tags != nil {
turbotTagsMap := map[string]string{}
for _, i := range data.Tags {
turbotTagsMap[*i.Key] = *i.Value
}
return turbotTagsMap, nil
}
return nil, nil
}
Loading
Loading