diff --git a/aws/plugin.go b/aws/plugin.go index f209b2376..d1bd3ef7f 100644 --- a/aws/plugin.go +++ b/aws/plugin.go @@ -99,6 +99,7 @@ func Plugin(ctx context.Context) *plugin.Plugin { "aws_appautoscaling_policy": tableAwsAppAutoScalingPolicy(ctx), "aws_appautoscaling_target": tableAwsAppAutoScalingTarget(ctx), "aws_appconfig_application": tableAwsAppConfigApplication(ctx), + "aws_application_signals_service_level_objective": tableAwsApplicationSignalsServiceLevelObjective(ctx), "aws_appstream_fleet": tableAwsAppStreamFleet(ctx), "aws_appstream_image": tableAwsAppStreamImage(ctx), "aws_appsync_graphql_api": tableAwsAppsyncGraphQLApi(ctx), @@ -467,7 +468,7 @@ func Plugin(ctx context.Context) *plugin.Plugin { "aws_securityhub_hub": tableAwsSecurityHub(ctx), "aws_securityhub_insight": tableAwsSecurityHubInsight(ctx), "aws_securityhub_member": tableAwsSecurityHubMember(ctx), - "aws_securityhub_enabled_product_subscription": tableAwsSecurityhubEnabledProductSubscription(ctx), + "aws_securityhub_enabled_product_subscription": tableAwsSecurityhubEnabledProductSubscription(ctx), "aws_securityhub_product": tableAwsSecurityhubProduct(ctx), "aws_securityhub_standards_control": tableAwsSecurityHubStandardsControl(ctx), "aws_securityhub_standards_subscription": tableAwsSecurityHubStandardsSubscription(ctx), diff --git a/aws/service.go b/aws/service.go index c66ec8360..87beda6e3 100644 --- a/aws/service.go +++ b/aws/service.go @@ -26,6 +26,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/apigatewayv2" "github.com/aws/aws-sdk-go-v2/service/appconfig" "github.com/aws/aws-sdk-go-v2/service/applicationautoscaling" + "github.com/aws/aws-sdk-go-v2/service/applicationsignals" "github.com/aws/aws-sdk-go-v2/service/apprunner" "github.com/aws/aws-sdk-go-v2/service/appstream" "github.com/aws/aws-sdk-go-v2/service/appsync" @@ -315,6 +316,17 @@ func ApplicationAutoScalingClient(ctx context.Context, d *plugin.QueryData) (*ap return applicationautoscaling.NewFromConfig(*cfg), nil } +func ApplicationSignalsClient(ctx context.Context, d *plugin.QueryData) (*applicationsignals.Client, error) { + cfg, err := getClientForQuerySupportedRegion(ctx, d, "application-signals") + if err != nil { + return nil, err + } + if cfg == nil { + return nil, nil + } + return applicationsignals.NewFromConfig(*cfg), nil +} + func AppRunnerClient(ctx context.Context, d *plugin.QueryData) (*apprunner.Client, error) { cfg, err := getClientForQuerySupportedRegion(ctx, d, appRunnerEndpoint.EndpointsID) if err != nil { diff --git a/aws/table_aws_application_signals_service_level_objective.go b/aws/table_aws_application_signals_service_level_objective.go new file mode 100644 index 000000000..48ad5f00c --- /dev/null +++ b/aws/table_aws_application_signals_service_level_objective.go @@ -0,0 +1,185 @@ +package aws + +import ( + "context" + "github.com/aws/aws-sdk-go-v2/service/applicationsignals" + applicationsignalsv1 "github.com/aws/aws-sdk-go/service/applicationsignals" + "strings" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/applicationsignals/types" + + "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" +) + +func tableAwsApplicationSignalsServiceLevelObjective(_ context.Context) *plugin.Table { + return &plugin.Table{ + Name: "aws_application_signals_service_level_objective", + Description: "AWS Application Signals Service Level Objective", + Get: &plugin.GetConfig{ + Hydrate: getApplicationSignalsServiceLevelObjective, + Tags: map[string]string{"service": "application-signals", "action": "GetApplicationSignalsServiceLevelObjective"}, + KeyColumns: plugin.AllColumns([]string{"arn", "name"}), + }, + List: &plugin.ListConfig{ + Hydrate: listApplicationSignalsServiceLevelObjectives, + Tags: map[string]string{"service": "application-signals", "action": "ListApplicationSignalsServiceLevelObjectives"}, + }, + HydrateConfig: []plugin.HydrateConfig{ + { + Func: getApplicationSignalsServiceLevelObjective, + Tags: map[string]string{"service": "application-signals", "action": "GetApplicationSignalsServiceLevelObjective"}, + }, + }, + GetMatrixItemFunc: SupportedRegionMatrix(applicationsignalsv1.EndpointsID), + Columns: awsRegionalColumns([]*plugin.Column{ + { + Name: "arn", + Description: "The Amazon Resource Name (ARN) of the service level objective.", + Type: proto.ColumnType_STRING, + }, + { + Name: "name", + Description: "The name of the service level objective.", + Type: proto.ColumnType_STRING, + }, + { + Name: "attainment_goal", + Description: "The attainment goal of the service level objective.", + Type: proto.ColumnType_DOUBLE, + Hydrate: getApplicationSignalsServiceLevelObjective, + Transform: transform.FromField("Goal.AttainmentGoal"), + }, + { + Name: "goal", + Description: "The goal of the service level objective.", + Type: proto.ColumnType_JSON, + Hydrate: getApplicationSignalsServiceLevelObjective, + }, + { + Name: "sli", + Description: "The sli of the service level objective.", + Type: proto.ColumnType_JSON, + Hydrate: getApplicationSignalsServiceLevelObjective, + }, + //// Steampipe Standard Columns + //{ + // Name: "tags", + // Description: resourceInterfaceDescription("tags"), + // Type: proto.ColumnType_JSON, + // Hydrate: getLogGroupTagging, + //}, + { + Name: "akas", + Description: resourceInterfaceDescription("akas"), + Type: proto.ColumnType_JSON, + Transform: transform.FromField("Arn").Transform(arnToAkas), + }, + }), + } +} + +//// LIST FUNCTION + +func listApplicationSignalsServiceLevelObjectives(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) { + svc, err := ApplicationSignalsClient(ctx, d) + + // Unsupported region check + if svc == nil { + return nil, nil + } + if err != nil { + plugin.Logger(ctx).Error("aws_application_signals_service_level_objective.listApplicationSignalsServiceLevelObjectives", "client_error", err) + return nil, err + } + + maxItems := int32(50) + + // Reduce the basic request limit down if the user has only requested a small number + if d.QueryContext.Limit != nil { + limit := int32(*d.QueryContext.Limit) + if limit < maxItems { + maxItems = int32(limit) + } + } + + input := &applicationsignals.ListServiceLevelObjectivesInput{ + MaxResults: &maxItems, + } + + paginator := applicationsignals.NewListServiceLevelObjectivesPaginator(svc, input, func(o *applicationsignals.ListServiceLevelObjectivesPaginatorOptions) { + o.Limit = maxItems + o.StopOnDuplicateToken = true + }) + + for paginator.HasMorePages() { + // apply rate limiting + d.WaitForListRateLimit(ctx) + + output, err := paginator.NextPage(ctx) + if err != nil { + plugin.Logger(ctx).Error("aws_application_signals_service_level_objective.listApplicationSignalsServiceLevelObjectives", "api_error", err) + return nil, err + } + + for _, sloSummary := range output.SloSummaries { + d.StreamListItem(ctx, sloSummary) + + // Context may get cancelled due to manual cancellation or if the limit has been reached + if d.RowsRemaining(ctx) == 0 { + return nil, nil + } + } + } + + return nil, nil +} + +//// HYDRATE FUNCTIONS + +func getApplicationSignalsServiceLevelObjective(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + arn := "" + + if h.Item != nil { + data := h.Item.(types.ServiceLevelObjectiveSummary) + arn = *data.Arn + } else { + arn = d.EqualsQualString("arn") + } + + // check if name is empty + if strings.TrimSpace(arn) == "" { + return nil, nil + } + + // Get client + svc, err := ApplicationSignalsClient(ctx, d) + + // Unsupported region check + if svc == nil { + return nil, nil + } + + // Unsupported region check + if svc == nil { + return nil, nil + } + if err != nil { + plugin.Logger(ctx).Error("aws_application_signals_service_level_objective.getApplicationSignalsServiceLevelObjective", "client_error", err) + return nil, err + } + + params := &applicationsignals.GetServiceLevelObjectiveInput{ + Id: aws.String(arn), + } + + item, err := svc.GetServiceLevelObjective(ctx, params) + if err != nil { + plugin.Logger(ctx).Error("aws_application_signals_service_level_objective.getApplicationSignalsServiceLevelObjective", "api_error", err) + return nil, err + } + + return item.Slo, nil +} diff --git a/docs/tables/aws_application_signals_service_level_objective.md b/docs/tables/aws_application_signals_service_level_objective.md new file mode 100644 index 000000000..cf59557a1 --- /dev/null +++ b/docs/tables/aws_application_signals_service_level_objective.md @@ -0,0 +1,58 @@ +--- +title: "Steampipe Table: aws_application_signals_service_level_objective - Query AWS Application Signals using SQL" +description: "Allows users to query AWS Application Signals to retrieve detailed information about each SLO, including its name, ARN, attainment_goal, goal and sli." +--- + +# Table: aws_application_signals_service_level_objective - Query AWS Application Signals Service Level Objective using SQL + +## Table Usage Guide + +The `aws_application_signals_service_level_objective` table in Steampipe provides you with information about SLOs within AWS Application Signals. This table allows you to query SLO details, including the name, ARN, attainment_goal, goal and sli, and associated metadata. + +## Examples + +### Basic info + +```sql+postgres +select + arn, + name, + attainment_goal, + goal, +from + aws_application_signals_service_level_objective; +``` + +```sql+sqlite +select + arn, + name, + attainment_goal, + goal, +from + aws_application_signals_service_level_objective; +``` + +### List service level objectives with select service level indicator details + +```sql+postgres +select + arn, + name, + sli::json -> 'ComparisonOperator' as "Must Be", + sli::json -> 'MetricThreshold' as "Threshold" + region +from + aws_application_signals_service_level_objective; +``` + +```sql+sqlite +select + arn, + name, + json_extract(sli, '$.ComparisonOperator') as "Must Be", + json_extract(sli, '$.MetricThreshold') as "Threshold" + region +from + aws_application_signals_service_level_objective +``` diff --git a/go.mod b/go.mod index 0d9b02069..0cd2fc4bf 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.22.4 toolchain go1.22.6 require ( - github.com/aws/aws-sdk-go v1.51.19 - github.com/aws/aws-sdk-go-v2 v1.27.0 + github.com/aws/aws-sdk-go v1.53.20 + github.com/aws/aws-sdk-go-v2 v1.30.5 github.com/aws/aws-sdk-go-v2/config v1.27.16 github.com/aws/aws-sdk-go-v2/credentials v1.17.16 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.21 @@ -19,6 +19,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.20.4 github.com/aws/aws-sdk-go-v2/service/appconfig v1.29.2 github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.27.4 + github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.4.0 github.com/aws/aws-sdk-go-v2/service/apprunner v1.28.8 github.com/aws/aws-sdk-go-v2/service/appstream v1.34.4 github.com/aws/aws-sdk-go-v2/service/appsync v1.31.4 @@ -166,8 +167,8 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect diff --git a/go.sum b/go.sum index 67ab2c9d2..35684eafd 100644 --- a/go.sum +++ b/go.sum @@ -203,10 +203,10 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.51.19 h1:jp/Vx/mUpXttthvvo/4/Nn/3+zumirIlAFkp1Irf1kM= -github.com/aws/aws-sdk-go v1.51.19/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo= -github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go v1.53.20 h1:cYWPvZLP1gPj5CfUdnfjaaA7WFK3FGoJ/R9+Ks1inU4= +github.com/aws/aws-sdk-go v1.53.20/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g= +github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= github.com/aws/aws-sdk-go-v2/config v1.27.16 h1:knpCuH7laFVGYTNd99Ns5t+8PuRjDn4HnnZK48csipM= @@ -217,10 +217,10 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 h1:dQLK4TjtnlRGb0czOht2Cev github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3/go.mod h1:TL79f2P6+8Q7dTsILpiVST+AL9lkF6PPGI167Ny0Cjw= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.21 h1:1v8Ii0MRVGYB/sdhkbxrtolCA7Tp+lGh+5OJTs5vmZ8= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.21/go.mod h1:cxdd1rc8yxCjKz28hi30XN1jDXr2DxZvD44vLxTz/bg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 h1:/FUtT3xsoHO3cfh+I/kCbcMCN98QZRsiFet/V8QkWSs= @@ -243,6 +243,8 @@ github.com/aws/aws-sdk-go-v2/service/appconfig v1.29.2 h1:Nm1Pqug23c/Ib+/FgwYpFZ github.com/aws/aws-sdk-go-v2/service/appconfig v1.29.2/go.mod h1:Z4uxjsQCQYIZQYOf5js8AN9B5ZCFfwRkEHuiihgjHWs= github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.27.4 h1:QGG9y+wEdP5KpTbcvpi8ETAoMq0zB6UJdqJ3JmVu/Wc= github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.27.4/go.mod h1:g7O+8ghAn49ysZShSpeOxIRiI0/BgPoqHwZFNKnykco= +github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.4.0 h1:xCO7ivLk/RAR372+4D9AQGFd/+Hs8Ehg79l9bfj32kQ= +github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.4.0/go.mod h1:oLl30psMIxqSF8EIbJBajb2VoLKcC97OVBUxaoBmsBU= github.com/aws/aws-sdk-go-v2/service/apprunner v1.28.8 h1:vTSRA431Gi6tQcUDfCTF1PwnLvw7M+7SoMWb0FRvKAY= github.com/aws/aws-sdk-go-v2/service/apprunner v1.28.8/go.mod h1:0ClIRoMxROYgDXb/kSvAsZSO41p4j9p4xkquAFzNEjM= github.com/aws/aws-sdk-go-v2/service/appstream v1.34.4 h1:chEtg7jpLbd+wzNEZR5Y7if5S3+zCL4HO892dk4JRHI=