diff --git a/aws/cost_explorer.go b/aws/cost_explorer.go index 2f92e78a7..3da7d06f4 100644 --- a/aws/cost_explorer.go +++ b/aws/cost_explorer.go @@ -26,6 +26,32 @@ func AllCostMetrics() []string { } } +func getMetricsByQueryContext(qc *plugin.QueryContext) []string { + queryColumns := qc.Columns + var metrics []string + + for _, c := range queryColumns { + switch c { + case "blended_cost_amount", "blended_cost_unit": + metrics = append(metrics, "BlendedCost") + case "unblended_cost_amount", "unblended_cost_unit": + metrics = append(metrics, "UnblendedCost") + case "net_unblended_cost_amount", "net_unblended_cost_unit": + metrics = append(metrics, "NetUnblendedCost") + case "amortized_cost_amount", "amortized_cost_unit": + metrics = append(metrics, "AmortizedCost") + case "net_amortized_cost_amount", "net_amortized_cost_unit": + metrics = append(metrics, "NetAmortizedCost") + case "usage_quantity_amount", "usage_quantity_unit": + metrics = append(metrics, "UsageQuantity") + case "normalized_usage_amount", "normalized_usage_unit": + metrics = append(metrics, "NormalizedUsageAmount") + } + } + + return removeDuplicates(metrics) +} + var costExplorerColumnDefs = []*plugin.Column{ { @@ -270,6 +296,7 @@ type CEQuals struct { // Quals stuff SearchStartTime *timestamp.Timestamp SearchEndTime *timestamp.Timestamp + Metrics string Granularity string DimensionType1 string DimensionType2 string diff --git a/aws/table_aws_cost_by_account_daily.go b/aws/table_aws_cost_by_account_daily.go index 25837c525..f6316e2ed 100644 --- a/aws/table_aws_cost_by_account_daily.go +++ b/aws/table_aws_cost_by_account_daily.go @@ -6,6 +6,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByLinkedAccountDaily(_ context.Context) *plugin.Table { @@ -14,11 +15,24 @@ func tableAwsCostByLinkedAccountDaily(_ context.Context) *plugin.Table { Description: "AWS Cost Explorer - Cost by Linked Account (Daily)", List: &plugin.ListConfig{ Hydrate: listCostByLinkedAccountDaily, - Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + }, + Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, }, Columns: awsGlobalRegionColumns( costExplorerColumns([]*plugin.Column{ - { Name: "linked_account_id", Description: "The AWS Account ID.", @@ -33,6 +47,6 @@ func tableAwsCostByLinkedAccountDaily(_ context.Context) *plugin.Table { //// LIST FUNCTION func listCostByLinkedAccountDaily(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) { - params := buildCostByLinkedAccountInput("DAILY") + params := buildCostByLinkedAccountInput(d, "DAILY") return streamCostAndUsage(ctx, d, params) } diff --git a/aws/table_aws_cost_by_account_monthly.go b/aws/table_aws_cost_by_account_monthly.go index b06109a7a..c5eebe3b7 100644 --- a/aws/table_aws_cost_by_account_monthly.go +++ b/aws/table_aws_cost_by_account_monthly.go @@ -11,6 +11,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByLinkedAccountMonthly(_ context.Context) *plugin.Table { @@ -19,11 +20,24 @@ func tableAwsCostByLinkedAccountMonthly(_ context.Context) *plugin.Table { Description: "AWS Cost Explorer - Cost by Linked Account (Monthly)", List: &plugin.ListConfig{ Hydrate: listCostByLinkedAccountMonthly, - Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + }, + Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, }, Columns: awsGlobalRegionColumns( costExplorerColumns([]*plugin.Column{ - { Name: "linked_account_id", Description: "The AWS Account ID.", @@ -38,12 +52,11 @@ func tableAwsCostByLinkedAccountMonthly(_ context.Context) *plugin.Table { //// LIST FUNCTION func listCostByLinkedAccountMonthly(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) { - params := buildCostByLinkedAccountInput("MONTHLY") - + params := buildCostByLinkedAccountInput(d, "MONTHLY") return streamCostAndUsage(ctx, d, params) } -func buildCostByLinkedAccountInput(granularity string) *costexplorer.GetCostAndUsageInput { +func buildCostByLinkedAccountInput(d *plugin.QueryData, granularity string) *costexplorer.GetCostAndUsageInput { timeFormat := "2006-01-02" if granularity == "HOURLY" { timeFormat = "2006-01-02T15:04:05Z" @@ -51,13 +64,26 @@ func buildCostByLinkedAccountInput(granularity string) *costexplorer.GetCostAndU endTime := time.Now().Format(timeFormat) startTime := getCEStartDateForGranularity(granularity).Format(timeFormat) + st, et := getSearchStartTImeAndSearchEndTime(d, granularity) + if st != "" { + startTime = st + } + if et != "" { + endTime = et + } + + selectedMetrics := AllCostMetrics() + if len(getMetricsByQueryContext(d.QueryContext)) > 0 { + selectedMetrics = getMetricsByQueryContext(d.QueryContext) + } + params := &costexplorer.GetCostAndUsageInput{ TimePeriod: &types.DateInterval{ Start: aws.String(startTime), End: aws.String(endTime), }, Granularity: types.Granularity(granularity), - Metrics: AllCostMetrics(), + Metrics: selectedMetrics, GroupBy: []types.GroupDefinition{ { Type: types.GroupDefinitionType("DIMENSION"), diff --git a/aws/table_aws_cost_by_record_type_daily.go b/aws/table_aws_cost_by_record_type_daily.go index 51a57b0ec..817be8b28 100644 --- a/aws/table_aws_cost_by_record_type_daily.go +++ b/aws/table_aws_cost_by_record_type_daily.go @@ -6,6 +6,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByRecordTypeDaily(_ context.Context) *plugin.Table { @@ -14,11 +15,24 @@ func tableAwsCostByRecordTypeDaily(_ context.Context) *plugin.Table { Description: "AWS Cost Explorer - Cost by Record Type (Daily)", List: &plugin.ListConfig{ Hydrate: listCostByRecordTypeDaily, - Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + }, + Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, }, Columns: awsGlobalRegionColumns( costExplorerColumns([]*plugin.Column{ - { Name: "linked_account_id", Description: "The linked AWS Account ID.", @@ -39,6 +53,6 @@ func tableAwsCostByRecordTypeDaily(_ context.Context) *plugin.Table { //// LIST FUNCTION func listCostByRecordTypeDaily(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) { - params := buildCostByRecordTypeInput("DAILY") + params := buildCostByRecordTypeInput(d, "DAILY") return streamCostAndUsage(ctx, d, params) } diff --git a/aws/table_aws_cost_by_record_type_monthly.go b/aws/table_aws_cost_by_record_type_monthly.go index b75f757db..80b705af9 100644 --- a/aws/table_aws_cost_by_record_type_monthly.go +++ b/aws/table_aws_cost_by_record_type_monthly.go @@ -11,6 +11,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByRecordTypeMonthly(_ context.Context) *plugin.Table { @@ -19,11 +20,24 @@ func tableAwsCostByRecordTypeMonthly(_ context.Context) *plugin.Table { Description: "AWS Cost Explorer - Cost by Record Type (Monthly)", List: &plugin.ListConfig{ Hydrate: listCostByRecordTypeMonthly, - Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + }, + Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, }, Columns: awsGlobalRegionColumns( costExplorerColumns([]*plugin.Column{ - { Name: "linked_account_id", Description: "The linked AWS Account ID.", @@ -44,12 +58,11 @@ func tableAwsCostByRecordTypeMonthly(_ context.Context) *plugin.Table { //// LIST FUNCTION func listCostByRecordTypeMonthly(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) { - params := buildCostByRecordTypeInput("MONTHLY") - + params := buildCostByRecordTypeInput(d, "MONTHLY") return streamCostAndUsage(ctx, d, params) } -func buildCostByRecordTypeInput(granularity string) *costexplorer.GetCostAndUsageInput { +func buildCostByRecordTypeInput(d *plugin.QueryData, granularity string) *costexplorer.GetCostAndUsageInput { timeFormat := "2006-01-02" if granularity == "HOURLY" { timeFormat = "2006-01-02T15:04:05Z" @@ -57,13 +70,26 @@ func buildCostByRecordTypeInput(granularity string) *costexplorer.GetCostAndUsag endTime := time.Now().Format(timeFormat) startTime := getCEStartDateForGranularity(granularity).Format(timeFormat) + st, et := getSearchStartTImeAndSearchEndTime(d, granularity) + if st != "" { + startTime = st + } + if et != "" { + endTime = et + } + + selectedMetrics := AllCostMetrics() + if len(getMetricsByQueryContext(d.QueryContext)) > 0 { + selectedMetrics = getMetricsByQueryContext(d.QueryContext) + } + params := &costexplorer.GetCostAndUsageInput{ TimePeriod: &types.DateInterval{ Start: aws.String(startTime), End: aws.String(endTime), }, Granularity: types.Granularity(granularity), - Metrics: AllCostMetrics(), + Metrics: selectedMetrics, GroupBy: []types.GroupDefinition{ { Type: types.GroupDefinitionType("DIMENSION"), diff --git a/aws/table_aws_cost_by_service_daily.go b/aws/table_aws_cost_by_service_daily.go index 2deba64c0..4d633ae61 100644 --- a/aws/table_aws_cost_by_service_daily.go +++ b/aws/table_aws_cost_by_service_daily.go @@ -6,6 +6,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByServiceDaily(_ context.Context) *plugin.Table { @@ -16,12 +17,27 @@ func tableAwsCostByServiceDaily(_ context.Context) *plugin.Table { Hydrate: listCostByServiceDaily, Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, KeyColumns: plugin.KeyColumnSlice{ - {Name: "service", Operators: []string{"=", "<>"}, Require: plugin.Optional}, + { + Name: "service", + Operators: []string{"=", "<>"}, + Require: plugin.Optional, + }, + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, }, }, Columns: awsGlobalRegionColumns( costExplorerColumns([]*plugin.Column{ - { Name: "service", Description: "The name of the AWS service.", diff --git a/aws/table_aws_cost_by_service_monthly.go b/aws/table_aws_cost_by_service_monthly.go index 65dba1cc7..ca2805e41 100644 --- a/aws/table_aws_cost_by_service_monthly.go +++ b/aws/table_aws_cost_by_service_monthly.go @@ -12,6 +12,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByServiceMonthly(_ context.Context) *plugin.Table { @@ -22,7 +23,23 @@ func tableAwsCostByServiceMonthly(_ context.Context) *plugin.Table { Hydrate: listCostByServiceMonthly, Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, KeyColumns: plugin.KeyColumnSlice{ - {Name: "service", Operators: []string{"=", "<>"}, Require: plugin.Optional}, + { + Name: "service", + Operators: []string{"=", "<>"}, + Require: plugin.Optional, + }, + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, }, }, Columns: awsGlobalRegionColumns( @@ -53,13 +70,26 @@ func buildCostByServiceInput(granularity string, d *plugin.QueryData) *costexplo endTime := time.Now().Format(timeFormat) startTime := getCEStartDateForGranularity(granularity).Format(timeFormat) + st, et := getSearchStartTImeAndSearchEndTime(d, granularity) + if st != "" { + startTime = st + } + if et != "" { + endTime = et + } + + selectedMetrics := AllCostMetrics() + if len(getMetricsByQueryContext(d.QueryContext)) > 0 { + selectedMetrics = getMetricsByQueryContext(d.QueryContext) + } + params := &costexplorer.GetCostAndUsageInput{ TimePeriod: &types.DateInterval{ Start: aws.String(startTime), End: aws.String(endTime), }, Granularity: types.Granularity(granularity), - Metrics: AllCostMetrics(), + Metrics: selectedMetrics, GroupBy: []types.GroupDefinition{ { Type: types.GroupDefinitionType("DIMENSION"), @@ -72,7 +102,7 @@ func buildCostByServiceInput(granularity string, d *plugin.QueryData) *costexplo for _, keyQual := range d.Table.List.KeyColumns { filterQual := d.Quals[keyQual.Name] - if filterQual == nil { + if filterQual == nil || keyQual.Name != "service" { continue } for _, qual := range filterQual.Quals { diff --git a/aws/table_aws_cost_by_service_usage_type_daily.go b/aws/table_aws_cost_by_service_usage_type_daily.go index 7e4cb25fb..3a19491b0 100644 --- a/aws/table_aws_cost_by_service_usage_type_daily.go +++ b/aws/table_aws_cost_by_service_usage_type_daily.go @@ -6,6 +6,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByServiceUsageTypeDaily(_ context.Context) *plugin.Table { @@ -16,8 +17,28 @@ func tableAwsCostByServiceUsageTypeDaily(_ context.Context) *plugin.Table { Hydrate: listCostByServiceAndUsageDaily, Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, KeyColumns: plugin.KeyColumnSlice{ - {Name: "service", Operators: []string{"=", "<>"}, Require: plugin.Optional}, - {Name: "usage_type", Operators: []string{"=", "<>"}, Require: plugin.Optional}, + { + Name: "service", + Operators: []string{"=", "<>"}, + Require: plugin.Optional, + }, + { + Name: "usage_type", + Operators: []string{"=", "<>"}, + Require: plugin.Optional, + }, + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, }, }, Columns: awsGlobalRegionColumns( diff --git a/aws/table_aws_cost_by_service_usage_type_monthly.go b/aws/table_aws_cost_by_service_usage_type_monthly.go index 9d59b55f2..bf8731db4 100644 --- a/aws/table_aws_cost_by_service_usage_type_monthly.go +++ b/aws/table_aws_cost_by_service_usage_type_monthly.go @@ -9,9 +9,11 @@ import ( "github.com/aws/aws-sdk-go-v2/service/costexplorer" "github.com/aws/aws-sdk-go-v2/service/costexplorer/types" + "github.com/turbot/go-kit/helpers" "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByServiceUsageTypeMonthly(_ context.Context) *plugin.Table { @@ -22,8 +24,28 @@ func tableAwsCostByServiceUsageTypeMonthly(_ context.Context) *plugin.Table { Hydrate: listCostByServiceAndUsageMonthly, Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, KeyColumns: plugin.KeyColumnSlice{ - {Name: "service", Operators: []string{"=", "<>"}, Require: plugin.Optional}, - {Name: "usage_type", Operators: []string{"=", "<>"}, Require: plugin.Optional}, + { + Name: "service", + Operators: []string{"=", "<>"}, + Require: plugin.Optional, + }, + { + Name: "usage_type", + Operators: []string{"=", "<>"}, + Require: plugin.Optional, + }, + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, }, }, Columns: awsGlobalRegionColumns( @@ -60,13 +82,26 @@ func buildCostByServiceAndUsageInput(granularity string, d *plugin.QueryData) *c endTime := time.Now().Format(timeFormat) startTime := getCEStartDateForGranularity(granularity).Format(timeFormat) + st, et := getSearchStartTImeAndSearchEndTime(d, granularity) + if st != "" { + startTime = st + } + if et != "" { + endTime = et + } + + selectedMetrics := AllCostMetrics() + if len(getMetricsByQueryContext(d.QueryContext)) > 0 { + selectedMetrics = getMetricsByQueryContext(d.QueryContext) + } + params := &costexplorer.GetCostAndUsageInput{ TimePeriod: &types.DateInterval{ Start: aws.String(startTime), End: aws.String(endTime), }, Granularity: types.Granularity(granularity), - Metrics: AllCostMetrics(), + Metrics: selectedMetrics, GroupBy: []types.GroupDefinition{ { Type: types.GroupDefinitionType("DIMENSION"), @@ -83,7 +118,7 @@ func buildCostByServiceAndUsageInput(granularity string, d *plugin.QueryData) *c for _, keyQual := range d.Table.List.KeyColumns { filterQual := d.Quals[keyQual.Name] - if filterQual == nil { + if filterQual == nil || !helpers.StringSliceContains([]string{"service", "usage_type"}, keyQual.Name) { continue } for _, qual := range filterQual.Quals { diff --git a/aws/table_aws_cost_by_tag.go b/aws/table_aws_cost_by_tag.go index 5738c0d3a..549038716 100644 --- a/aws/table_aws_cost_by_tag.go +++ b/aws/table_aws_cost_by_tag.go @@ -13,6 +13,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostByTag(_ context.Context) *plugin.Table { @@ -21,16 +22,38 @@ func tableAwsCostByTag(_ context.Context) *plugin.Table { Description: "AWS Cost Explorer - Cost By Tags", List: &plugin.ListConfig{ KeyColumns: []*plugin.KeyColumn{ - {Name: "granularity", Require: plugin.Required}, - {Name: "tag_key_1", Require: plugin.Required}, - {Name: "tag_key_2", Operators: []string{"=", "<>"}, Require: plugin.Optional, CacheMatch: "exact"}, + { + Name: "granularity", + Require: plugin.Required, + }, + { + Name: "tag_key_1", + Require: plugin.Required, + }, + { + Name: "tag_key_2", + Operators: []string{"=", "<>"}, + Require: plugin.Optional, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, }, Hydrate: listCostAndUsageByTags, Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, }, Columns: awsGlobalRegionColumns( costExplorerColumns([]*plugin.Column{ - // Quals columns - to filter the lookups { Name: "granularity", @@ -83,13 +106,26 @@ func buildInputFromTagKeyAndTagValueQuals(ctx context.Context, d *plugin.QueryDa endTime := time.Now().Format(timeFormat) startTime := getCEStartDateForGranularity(granularity).Format(timeFormat) + st, et := getSearchStartTImeAndSearchEndTime(d, granularity) + if st != "" { + startTime = st + } + if et != "" { + endTime = et + } + + selectedMetrics := AllCostMetrics() + if len(getMetricsByQueryContext(d.QueryContext)) > 0 { + selectedMetrics = getMetricsByQueryContext(d.QueryContext) + } + params := &costexplorer.GetCostAndUsageInput{ TimePeriod: &types.DateInterval{ Start: aws.String(startTime), End: aws.String(endTime), }, Granularity: types.Granularity(granularity), - Metrics: AllCostMetrics(), + Metrics: selectedMetrics, } tagKey1 := d.EqualsQualString("tag_key_1") tagKey2 := d.EqualsQualString("tag_key_2") diff --git a/aws/table_aws_cost_forecast_daily.go b/aws/table_aws_cost_forecast_daily.go index 894420618..97adda16c 100644 --- a/aws/table_aws_cost_forecast_daily.go +++ b/aws/table_aws_cost_forecast_daily.go @@ -11,6 +11,7 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostForecastDaily(_ context.Context) *plugin.Table { @@ -19,7 +20,21 @@ func tableAwsCostForecastDaily(_ context.Context) *plugin.Table { Description: "AWS Cost Explorer - Cost Forecast (Daily)", List: &plugin.ListConfig{ Hydrate: listCostForecastDaily, - Tags: map[string]string{"service": "ce", "action": "GetCostForecast"}, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + }, + Tags: map[string]string{"service": "ce", "action": "GetCostForecast"}, }, Columns: awsGlobalRegionColumns([]*plugin.Column{ { @@ -39,8 +54,7 @@ func tableAwsCostForecastDaily(_ context.Context) *plugin.Table { Description: "Average forecasted value", Type: proto.ColumnType_DOUBLE, }, - }, - ), + }), } } @@ -55,7 +69,7 @@ func listCostForecastDaily(ctx context.Context, d *plugin.QueryData, _ *plugin.H return nil, err } - params := buildCostForecastInput(d.EqualsQuals, "DAILY") + params := buildCostForecastInput(d, "DAILY") output, err := svc.GetCostForecast(ctx, params) if err != nil { @@ -75,7 +89,7 @@ func listCostForecastDaily(ctx context.Context, d *plugin.QueryData, _ *plugin.H return nil, nil } -func buildCostForecastInput(_ map[string]*proto.QualValue, granularity string) *costexplorer.GetCostForecastInput { +func buildCostForecastInput(d *plugin.QueryData, granularity string) *costexplorer.GetCostForecastInput { // TO DO - specify metric as qual? get all cost metrics in parallel? //metric := strings.ToUpper(keyQuals["metric"].GetStringValue()) @@ -90,6 +104,15 @@ func buildCostForecastInput(_ map[string]*proto.QualValue, granularity string) * startTime := time.Now().UTC().Format(timeFormat) endTime := getForecastEndDateForGranularity(granularity).Format(timeFormat) + // Get search start time and search end time based on the quals value with operator + st, et := getSearchStartTImeAndSearchEndTime(d, granularity) + if st != "" { + startTime = st + } + if et != "" { + endTime = et + } + params := &costexplorer.GetCostForecastInput{ TimePeriod: &types.DateInterval{ Start: aws.String(startTime), diff --git a/aws/table_aws_cost_forecast_monthly.go b/aws/table_aws_cost_forecast_monthly.go index 91efa2202..e650029fd 100644 --- a/aws/table_aws_cost_forecast_monthly.go +++ b/aws/table_aws_cost_forecast_monthly.go @@ -6,15 +6,30 @@ import ( "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" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) -func tableAwsCostForecastMonthly(_ context.Context) *plugin.Table { +func tableAwsCostForecastMonthly(ctx context.Context) *plugin.Table { return &plugin.Table{ Name: "aws_cost_forecast_monthly", Description: "AWS Cost Explorer - Cost Forecast (Monthly)", List: &plugin.ListConfig{ Hydrate: listCostForecastMonthly, Tags: map[string]string{"service": "ce", "action": "GetCostForecast"}, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + }, }, Columns: awsGlobalRegionColumns([]*plugin.Column{ { @@ -34,8 +49,7 @@ func tableAwsCostForecastMonthly(_ context.Context) *plugin.Table { Description: "Average forecasted value", Type: proto.ColumnType_DOUBLE, }, - }, - ), + }), } } @@ -50,7 +64,7 @@ func listCostForecastMonthly(ctx context.Context, d *plugin.QueryData, _ *plugin return nil, err } - params := buildCostForecastInput(d.EqualsQuals, "MONTHLY") + params := buildCostForecastInput(d, "MONTHLY") output, err := svc.GetCostForecast(ctx, params) if err != nil { diff --git a/aws/table_aws_cost_usage.go b/aws/table_aws_cost_usage.go index 4839e3ced..cb0b7a0b7 100644 --- a/aws/table_aws_cost_usage.go +++ b/aws/table_aws_cost_usage.go @@ -11,6 +11,7 @@ import ( "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" "github.com/turbot/steampipe-plugin-sdk/v5/plugin" + "github.com/turbot/steampipe-plugin-sdk/v5/query_cache" ) func tableAwsCostAndUsage(_ context.Context) *plugin.Table { @@ -18,10 +19,35 @@ func tableAwsCostAndUsage(_ context.Context) *plugin.Table { Name: "aws_cost_usage", Description: "AWS Cost Explorer - Cost and Usage", List: &plugin.ListConfig{ - //KeyColumns: plugin.AllColumns([]string{"search_start_time", "search_end_time", "granularity", "dimension_type_1", "dimension_type_2"}), - KeyColumns: plugin.AllColumns([]string{"granularity", "dimension_type_1", "dimension_type_2"}), - Hydrate: listCostAndUsage, - Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, + KeyColumns: plugin.KeyColumnSlice{ + { + Name: "granularity", + Require: plugin.Required, + }, + { + Name: "dimension_type_1", + Require: plugin.Required, + }, + { + Name: "dimension_type_2", + Require: plugin.Required, + }, + { + Name: "period_start", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + { + Name: "period_end", + Require: plugin.Optional, + Operators: []string{">", ">=", "=", "<", "<="}, + CacheMatch: query_cache.CacheMatchExact, + }, + }, + + Hydrate: listCostAndUsage, + Tags: map[string]string{"service": "ce", "action": "GetCostAndUsage"}, }, Columns: awsGlobalRegionColumns( costExplorerColumns([]*plugin.Column{ @@ -35,24 +61,23 @@ func tableAwsCostAndUsage(_ context.Context) *plugin.Table { Description: "Valid values are AZ, INSTANCE_TYPE, LINKED_ACCOUNT, OPERATION, PURCHASE_TYPE, SERVICE, USAGE_TYPE, PLATFORM, TENANCY, RECORD_TYPE, LEGAL_ENTITY_NAME, DEPLOYMENT_OPTION, DATABASE_ENGINE, CACHE_ENGINE, INSTANCE_TYPE_FAMILY, REGION, BILLING_ENTITY, RESERVATION_ID, SAVINGS_PLANS_TYPE, SAVINGS_PLAN_ARN, OPERATING_SYSTEM", Type: proto.ColumnType_STRING, }, - - // Quals columns - to filter the lookups { - Name: "granularity", - Description: "", - Type: proto.ColumnType_STRING, + Name: "search_start_time", + Description: "[Deprecated] The beginning of the time period.", + Type: proto.ColumnType_TIMESTAMP, Hydrate: hydrateCostAndUsageQuals, }, { - Name: "search_start_time", - Description: "", + Name: "search_end_time", + Description: "[Deprecated] The end of the time period.", Type: proto.ColumnType_TIMESTAMP, Hydrate: hydrateCostAndUsageQuals, }, + // Quals columns - to filter the lookups { - Name: "search_end_time", + Name: "granularity", Description: "", - Type: proto.ColumnType_TIMESTAMP, + Type: proto.ColumnType_STRING, Hydrate: hydrateCostAndUsageQuals, }, { @@ -109,12 +134,12 @@ func tableAwsCostAndUsage(_ context.Context) *plugin.Table { //// LIST FUNCTION func listCostAndUsage(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) { - params := buildInputFromQuals(d.EqualsQuals) + params := buildInputFromQuals(ctx, d) return streamCostAndUsage(ctx, d, params) } -func buildInputFromQuals(keyQuals map[string]*proto.QualValue) *costexplorer.GetCostAndUsageInput { - granularity := strings.ToUpper(keyQuals["granularity"].GetStringValue()) +func buildInputFromQuals(ctx context.Context, keyQuals *plugin.QueryData) *costexplorer.GetCostAndUsageInput { + granularity := strings.ToUpper(keyQuals.EqualsQuals["granularity"].GetStringValue()) timeFormat := "2006-01-02" if granularity == "HOURLY" { timeFormat = "2006-01-02T15:04:05Z" @@ -122,8 +147,21 @@ func buildInputFromQuals(keyQuals map[string]*proto.QualValue) *costexplorer.Get endTime := time.Now().Format(timeFormat) startTime := getCEStartDateForGranularity(granularity).Format(timeFormat) - dim1 := strings.ToUpper(keyQuals["dimension_type_1"].GetStringValue()) - dim2 := strings.ToUpper(keyQuals["dimension_type_2"].GetStringValue()) + st, et := getSearchStartTImeAndSearchEndTime(keyQuals, granularity) + if st != "" { + startTime = st + } + if et != "" { + endTime = et + } + + selectedMetrics := AllCostMetrics() + if len(getMetricsByQueryContext(keyQuals.QueryContext)) > 0 { + selectedMetrics = getMetricsByQueryContext(keyQuals.QueryContext) + } + + dim1 := strings.ToUpper(keyQuals.EqualsQuals["dimension_type_1"].GetStringValue()) + dim2 := strings.ToUpper(keyQuals.EqualsQuals["dimension_type_2"].GetStringValue()) params := &costexplorer.GetCostAndUsageInput{ TimePeriod: &types.DateInterval{ @@ -131,7 +169,7 @@ func buildInputFromQuals(keyQuals map[string]*proto.QualValue) *costexplorer.Get End: aws.String(endTime), }, Granularity: types.Granularity(granularity), - Metrics: AllCostMetrics(), + Metrics: selectedMetrics, } var groupings []types.GroupDefinition if dim1 != "" { @@ -151,6 +189,56 @@ func buildInputFromQuals(keyQuals map[string]*proto.QualValue) *costexplorer.Get return params } +func getSearchStartTImeAndSearchEndTime(keyQuals *plugin.QueryData, granularity string) (string, string) { + timeFormat := "2006-01-02" + if granularity == "HOURLY" { + timeFormat = "2006-01-02T15:04:05Z" + } + + st, et := "", "" + + if keyQuals.Quals["period_start"] != nil && !(len(keyQuals.Quals["period_start"].Quals) > 1) { + for _, q := range keyQuals.Quals["period_start"].Quals { + t := q.Value.GetTimestampValue().AsTime().Format(timeFormat) + switch q.Operator { + case "=", ">=", ">": + st = t + case "<", "<=": + et = t + } + } + } + + // The API supports a single value with the '=' operator. + // For queries like: "period_end BETWEEN current_timestamp - interval '31d' AND current_timestamp - interval '1d'", the FDW parses the query parameters with multiple qualifiers. + // In this case, we will have multiple qualifiers with operators such as: + // 1. The length of keyQuals.Quals["period_end"].Quals will be 2. + // 2. The qualifier values would be "2024-05-10" with the '>=' operator and "2024-06-09" with the '<=' operator. + // Plugin Log: + // 2024-06-10 11:17:39.071 UTC [DEBUG] steampipe-plugin-aws.plugin: [ERROR] 1718018259212: Period end Scan Length ===>>> : EXTRA_VALUE_AT_END=2 + // 2024-06-10 11:17:39.071 UTC [DEBUG] steampipe-plugin-aws.plugin: [ERROR] 1718018259212: Period End => : >=2024-05-10 + // 2024-06-10 11:17:39.071 UTC [DEBUG] steampipe-plugin-aws.plugin: [ERROR] 1718018259212: Period End => : <=2024-06-09 + // In this scenario, manipulating the start and end time is a bit difficult and challenging. + // Let the API fetch all the rows, and filtering will occur at the Steampipe level. + + if keyQuals.Quals["period_end"] != nil && !(len(keyQuals.Quals["period_end"].Quals) > 1) { + for _, q := range keyQuals.Quals["period_end"].Quals { + t := q.Value.GetTimestampValue().AsTime().Format(timeFormat) + switch q.Operator { + case "=", ">=", ">": + if st == "" { + st = t + } + case "<", "<=": + if et == "" { + et = t + } + } + } + } + return st, et +} + //// HYDRATE FUNCTIONS // func hydrateKeyQuals(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { diff --git a/aws/utils.go b/aws/utils.go index affeed0c4..3a053a989 100644 --- a/aws/utils.go +++ b/aws/utils.go @@ -89,6 +89,20 @@ func getLastPathElement(path string) string { return pathItems[len(pathItems)-1] } +// removeDuplicates removes duplicates from a slice of strings. +func removeDuplicates(strings []string) []string { + seen := make(map[string]bool) + result := []string{} + + for _, s := range strings { + if _, ok := seen[s]; !ok { + seen[s] = true + result = append(result, s) + } + } + return result +} + func lastPathElement(_ context.Context, d *transform.TransformData) (interface{}, error) { return getLastPathElement(types.SafeString(d.Value)), nil } diff --git a/docs/tables/aws_cost_by_account_daily.md b/docs/tables/aws_cost_by_account_daily.md index 1bfcd292a..34e362628 100644 --- a/docs/tables/aws_cost_by_account_daily.md +++ b/docs/tables/aws_cost_by_account_daily.md @@ -15,6 +15,9 @@ Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -30,7 +33,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_account_daily order by linked_account_id, @@ -46,7 +49,7 @@ select CAST(amortized_cost_amount AS REAL) AS amortized_cost_amount, CAST(net_unblended_cost_amount AS REAL) AS net_unblended_cost_amount, CAST(net_amortized_cost_amount AS REAL) AS net_amortized_cost_amount -from +from aws_cost_by_account_daily order by linked_account_id, @@ -62,7 +65,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_account_daily group by linked_account_id @@ -76,7 +79,7 @@ select min(unblended_cost_amount) as min, max(unblended_cost_amount) as max, avg(unblended_cost_amount) as average -from +from aws_cost_by_account_daily group by linked_account_id @@ -95,12 +98,62 @@ with ranked_costs as ( period_start, unblended_cost_amount::numeric::money, rank() over(partition by linked_account_id order by unblended_cost_amount desc) - from + from aws_cost_by_account_daily ) select * from ranked_costs where rank <= 10; ``` ```sql+sqlite -Error: SQLite does not support the rank window function. +with ranked_costs as ( + select + linked_account_id, + period_start, + cast(unblended_cost_amount as real) as unblended_cost_amount, + rank() over (partition by linked_account_id order by unblended_cost_amount desc) as rnk + from + aws_cost_by_account_daily +) +select * from ranked_costs where rnk <= 10; +``` + +### Get the specific costs within a given time frame +Analyze your AWS accounts' daily specific expenditure to identify the minimum, maximum, and average costs whin a given time frame. + +```sql+postgres +select + linked_account_id, + period_start, + blended_cost_amount::numeric::money, + unblended_cost_amount::numeric::money, + amortized_cost_amount::numeric::money, + net_unblended_cost_amount::numeric::money, + net_amortized_cost_amount::numeric::money +from + aws_cost_by_account_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; +``` + +```sql+sqlite +select + linked_account_id, + period_start, + blended_cost_amount::numeric::money, + unblended_cost_amount::numeric::money, + amortized_cost_amount::numeric::money, + net_unblended_cost_amount::numeric::money, + net_amortized_cost_amount::numeric::money +from + aws_cost_by_account_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_by_account_monthly.md b/docs/tables/aws_cost_by_account_monthly.md index f0d1285e4..e777f1fa7 100644 --- a/docs/tables/aws_cost_by_account_monthly.md +++ b/docs/tables/aws_cost_by_account_monthly.md @@ -11,14 +11,19 @@ The AWS Cost Explorer Service provides insights into your AWS costs and usage. I The `aws_cost_by_account_monthly` table in Steampipe provides you with information about your monthly AWS costs per account. This table allows you, as a financial analyst or DevOps engineer, to query cost-specific details, including the total amount spent, the currency code, and the associated AWS account. You can utilize this table to gain insights on your AWS spending and to manage your budget more effectively. The schema outlines the various attributes of your AWS cost, including the account ID, the month, the total amount, and the currency code. -Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_account_monthly` table provides a simplified view of cost for your account (or all linked accounts when run against the organization master), summarized by month, for the last year. +Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_account_monthly` table provides a simplified view of cost for your account (or all linked accounts when run against the organization master), summarized by month, for the last year. **Important Notes** + - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples ### Basic info + This query allows you to analyze the monthly costs associated with each linked account on AWS. It helps in understanding the financial impact of different accounts and provides insights for better cost management. ```sql+postgres @@ -30,7 +35,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_account_monthly order by linked_account_id, @@ -46,16 +51,15 @@ select CAST(amortized_cost_amount AS REAL) AS amortized_cost_amount, CAST(net_unblended_cost_amount AS REAL) AS net_unblended_cost_amount, CAST(net_amortized_cost_amount AS REAL) AS net_amortized_cost_amount -from +from aws_cost_by_account_monthly order by linked_account_id, period_start; ``` - - ### Min, Max, and average monthly unblended_cost_amount by account + Analyze your AWS accounts' monthly expenditure to identify the minimum, maximum, and average costs. This information can help in budgeting and managing your cloud expenses more effectively. ```sql+postgres @@ -64,7 +68,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_account_monthly group by linked_account_id @@ -78,7 +82,7 @@ select min(unblended_cost_amount) as min, max(unblended_cost_amount) as max, avg(unblended_cost_amount) as average -from +from aws_cost_by_account_monthly group by linked_account_id @@ -86,8 +90,8 @@ order by linked_account_id; ``` - ### Ranked - Most expensive months (unblended_cost_amount) by account + Analyze your spending patterns by identifying the months with the highest costs for each linked AWS account. This can help manage your budget by highlighting periods of increased expenditure. ```sql+postgres @@ -96,7 +100,7 @@ select period_start, unblended_cost_amount::numeric::money, rank() over(partition by linked_account_id order by unblended_cost_amount desc) -from +from aws_cost_by_account_monthly; ``` @@ -105,6 +109,7 @@ Error: SQLite does not support the rank window function. ``` ### Month on month growth (unblended_cost_amount) by account + This query is designed to analyze monthly expenditure trends across different accounts. It helps users identify any significant changes in costs, which can be useful for budgeting and cost management purposes. ```sql+postgres @@ -113,7 +118,7 @@ with cost_data as ( linked_account_id, period_start, unblended_cost_amount as this_month, - lag(unblended_cost_amount,-1) over(partition by linked_account_id order by period_start desc) as previous_month + lag(unblended_cost_amount, -1) over(partition by linked_account_id order by period_start desc) as previous_month from aws_cost_by_account_monthly ) @@ -137,7 +142,7 @@ with cost_data as ( period_start, unblended_cost_amount as this_month, lag(unblended_cost_amount, -1) over(partition by linked_account_id order by period_start desc) as previous_month - from + from aws_cost_by_account_monthly ) select @@ -150,4 +155,45 @@ from cost_data order by linked_account_id; -``` \ No newline at end of file +``` + +### Get the specific costs within a given time frame +Analyze your AWS accounts' monthly specific expenditure to identify the minimum, maximum, and average costs whin a given time frame. + +```sql+postgres +select + linked_account_id, + period_start, + blended_cost_amount::numeric::money, + unblended_cost_amount::numeric::money, + amortized_cost_amount::numeric::money, + net_unblended_cost_amount::numeric::money, + net_amortized_cost_amount::numeric::money +from + aws_cost_by_account_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; +``` + +```sql+sqlite +select + linked_account_id, + period_start, + blended_cost_amount AS blended_cost_amount, + unblended_cost_amount AS unblended_cost_amount, + amortized_cost_amount AS amortized_cost_amount, + net_unblended_cost_amount AS net_unblended_cost_amount, + net_amortized_cost_amount AS net_amortized_cost_amount +from + aws_cost_by_account_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; +``` diff --git a/docs/tables/aws_cost_by_record_type_daily.md b/docs/tables/aws_cost_by_record_type_daily.md index 1b4cc7361..77577699a 100644 --- a/docs/tables/aws_cost_by_record_type_daily.md +++ b/docs/tables/aws_cost_by_record_type_daily.md @@ -11,10 +11,13 @@ The AWS Cost and Usage Report is a comprehensive resource that provides detailed The `aws_cost_by_record_type_daily` table in Steampipe provides you with information about AWS costs incurred per record type on a daily basis. This table allows you as a financial analyst, DevOps engineer, or other professional to query cost-specific details, including the linked account, service, usage type, and operation. You can utilize this table to gather insights on cost distribution, such as costs associated with different services, usage types, and operations. The schema outlines the various attributes of the cost record, including the record id, record type, billing period start date, and cost. -Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_record_type_daily` table provides a simplified view of cost for your account (or all linked accounts when run against the organization master) as per record types (fees, usage, costs, tax refunds, and credits), summarized by day, for the last year. +Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_record_type_daily` table provides a simplified view of cost for your account (or all linked accounts when run against the organization master) as per record types (fees, usage, costs, tax refunds, and credits), summarized by day, for the last year. **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -31,7 +34,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_record_type_daily order by linked_account_id, @@ -48,7 +51,7 @@ select CAST(amortized_cost_amount AS REAL) AS amortized_cost_amount, CAST(net_unblended_cost_amount AS REAL) AS net_unblended_cost_amount, CAST(net_amortized_cost_amount AS REAL) AS net_amortized_cost_amount -from +from aws_cost_by_record_type_daily order by linked_account_id, @@ -65,7 +68,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_record_type_daily group by linked_account_id, @@ -81,7 +84,7 @@ select min(unblended_cost_amount) as min, max(unblended_cost_amount) as max, avg(unblended_cost_amount) as average -from +from aws_cost_by_record_type_daily group by linked_account_id, @@ -101,7 +104,7 @@ with ranked_costs as ( period_start, unblended_cost_amount::numeric::money, rank() over(partition by linked_account_id, record_type order by unblended_cost_amount desc) - from + from aws_cost_by_record_type_daily ) select * from ranked_costs where rank <= 10; @@ -109,4 +112,39 @@ select * from ranked_costs where rank <= 10; ```sql+sqlite Error: SQLite does not support the rank window function. +``` + +### Get only daily amortized cost details by account and record type within a custom time frame +Focusing on amortized costs by account and record type, organizations can achieve a clearer, more detailed understanding of their spending patterns. + +```sql+postgres +select + linked_account_id, + record_type, + period_start, + amortized_cost_amount::numeric::money +from + aws_cost_by_record_type_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; +``` + +```sql+sqlite +select + linked_account_id, + record_type, + period_start, + case(amortized_cost_amount as real) as amortized_cost_amount +from + aws_cost_by_record_type_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_by_record_type_monthly.md b/docs/tables/aws_cost_by_record_type_monthly.md index e3c6c4706..a0f5b6c76 100644 --- a/docs/tables/aws_cost_by_record_type_monthly.md +++ b/docs/tables/aws_cost_by_record_type_monthly.md @@ -11,10 +11,13 @@ The AWS Cost and Usage Report service provides comprehensive cost and usage data The `aws_cost_by_record_type_monthly` table in Steampipe provides you with information about AWS Cost and Usage Report Records, specifically detailing costs incurred by different record types on a monthly basis. This table allows you, whether you're a DevOps engineer or a financial analyst, to query cost-specific details, including service usage, cost allocation, and associated metadata. You can utilize this table to gather insights on AWS costs, such as costs associated with specific AWS services, cost trends over time, and cost allocation across different record types. The schema outlines the various attributes of the cost and usage report record, including the record type, usage type, operation, and cost. -Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_record_type_monthly` table provides a simplified view of cost for your account (or all linked accounts when run against the organization master) as per record types (fees, usage, costs, tax refunds, and credits), summarized by month, for the last year. +Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_record_type_monthly` table provides a simplified view of cost for your account (or all linked accounts when run against the organization master) as per record types (fees, usage, costs, tax refunds, and credits), summarized by month, for the last year. **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request will incur a cost of $0.01 for you. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -31,7 +34,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_record_type_monthly order by linked_account_id, @@ -48,7 +51,7 @@ select CAST(amortized_cost_amount AS REAL) AS amortized_cost_amount, CAST(net_unblended_cost_amount AS REAL) AS net_unblended_cost_amount, CAST(net_amortized_cost_amount AS REAL) AS net_amortized_cost_amount -from +from aws_cost_by_record_type_monthly order by linked_account_id, @@ -65,7 +68,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_record_type_monthly group by linked_account_id, @@ -81,7 +84,7 @@ select min(unblended_cost_amount) as min, max(unblended_cost_amount) as max, avg(unblended_cost_amount) as average -from +from aws_cost_by_record_type_monthly group by linked_account_id, @@ -100,7 +103,7 @@ select period_start, unblended_cost_amount::numeric::money, rank() over(partition by linked_account_id, record_type order by unblended_cost_amount desc) -from +from aws_cost_by_record_type_monthly; ``` @@ -111,13 +114,48 @@ select period_start, unblended_cost_amount, ( - select count(*) + 1 + select count(*) + 1 from aws_cost_by_record_type_monthly as b - where - a.linked_account_id = b.linked_account_id and - a.record_type = b.record_type and + where + a.linked_account_id = b.linked_account_id and + a.record_type = b.record_type and a.unblended_cost_amount < b.unblended_cost_amount ) -from +from aws_cost_by_record_type_monthly as a; +``` + +### Get only monthly amortized cost details by account and record type within a custom time frame +Focusing on amortized costs by account and record type, organizations can achieve a clearer, more detailed understanding of their spending patterns. + +```sql+postgres +select + linked_account_id, + record_type, + period_start, + amortized_cost_amount::numeric::money +from + aws_cost_by_record_type_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; +``` + +```sql+sqlite +select + linked_account_id, + record_type, + period_start, + case(amortized_cost_amount as real) as amortized_cost_amount +from + aws_cost_by_record_type_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + linked_account_id, + period_start; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_by_service_daily.md b/docs/tables/aws_cost_by_service_daily.md index 5d8f654e0..498142446 100644 --- a/docs/tables/aws_cost_by_service_daily.md +++ b/docs/tables/aws_cost_by_service_daily.md @@ -11,10 +11,13 @@ The AWS Cost Explorer is a tool that allows you to visualize, understand, and ma The `aws_cost_by_service_daily` table in Steampipe provides you with information about the daily cost breakdown by AWS service within AWS Cost Explorer. This table allows you, as a financial analyst or cloud administrator, to query cost-specific details, including total cost, unit, and service name on a daily basis. You can utilize this table to track your spending on AWS services, monitor cost trends, and identify potential cost-saving opportunities. The schema outlines the various attributes of your cost data, including your linked account, service, currency, and amount. -Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_daily` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by day, for the last year. +Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_daily` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by day, for the last year. **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -30,7 +33,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_service_daily order by service, @@ -46,7 +49,7 @@ select cast(amortized_cost_amount as decimal), cast(net_unblended_cost_amount as decimal), cast(net_amortized_cost_amount as decimal) -from +from aws_cost_by_service_daily order by service, @@ -62,7 +65,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_daily group by service @@ -76,7 +79,7 @@ select min(unblended_cost_amount) as min, max(unblended_cost_amount) as max, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_daily group by service @@ -92,7 +95,7 @@ select service, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_daily group by service @@ -106,7 +109,7 @@ select service, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_daily group by service @@ -123,7 +126,7 @@ select service, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_daily group by service @@ -137,7 +140,7 @@ select service, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_daily group by service @@ -157,7 +160,7 @@ with ranked_costs as ( period_start, unblended_cost_amount::numeric::money, rank() over(partition by service order by unblended_cost_amount desc) - from + from aws_cost_by_service_daily ) select * from ranked_costs where rank <= 10; @@ -165,4 +168,39 @@ select * from ranked_costs where rank <= 10; ```sql+sqlite Error: SQLite does not support the rank window function. +``` + +### Get only daily blended and unblended cost details for the services within a custom time frame +Focusing on blended and unblended costs within a custom time frame offers a clear, detailed perspective on where money is being spent in the cloud, enabling more strategic financial planning and better resource allocation. + +```sql+postgres +select + service, + period_start, + blended_cost_amount::numeric::money, + unblended_cost_amount::numeric::money +from + aws_cost_by_service_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + service, + period_start; +``` + +```sql+sqlite +select + service, + period_start, + cast(blended_cost_amount as decimal), + cast(unblended_cost_amount as decimal) +from + aws_cost_by_service_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + service, + period_start; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_by_service_monthly.md b/docs/tables/aws_cost_by_service_monthly.md index a381370d5..fcf43925e 100644 --- a/docs/tables/aws_cost_by_service_monthly.md +++ b/docs/tables/aws_cost_by_service_monthly.md @@ -11,11 +11,14 @@ The AWS Cost Explorer Service provides detailed information about your AWS costs The `aws_cost_by_service_monthly` table in Steampipe provides you with information about the monthly cost breakdown by service within AWS Cost Explorer. This table allows you, as a financial analyst, DevOps engineer, or other stakeholder, to query cost-specific details, including the service name, the cost associated with it, and the currency code. You can utilize this table to gather insights on cost management, such as tracking AWS expenses, identifying cost trends, and auditing. The schema outlines the various attributes of the cost information, including the service name, cost, and currency code. -Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_monthly` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by month, for the last year. +Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_monthly` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by month, for the last year. **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -31,7 +34,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_service_monthly order by service, @@ -47,7 +50,7 @@ select cast(amortized_cost_amount as decimal), cast(net_unblended_cost_amount as decimal), cast(net_amortized_cost_amount as decimal) -from +from aws_cost_by_service_monthly order by service, @@ -65,7 +68,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_monthly group by service @@ -79,7 +82,7 @@ select min(unblended_cost_amount) as min, max(unblended_cost_amount) as max, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_monthly group by service @@ -95,7 +98,7 @@ select service, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_monthly group by service @@ -109,7 +112,7 @@ select service, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_monthly group by service @@ -127,7 +130,7 @@ select service, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_monthly group by service @@ -141,7 +144,7 @@ select service, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_monthly group by service @@ -161,7 +164,7 @@ with ranked_costs as ( period_start, unblended_cost_amount::numeric::money, rank() over(partition by service order by unblended_cost_amount desc) - from + from aws_cost_by_service_monthly ) select * from ranked_costs where rank = 1; @@ -180,8 +183,8 @@ with cost_data as ( service, period_start, unblended_cost_amount as this_month, - lag(unblended_cost_amount,-1) over(partition by service order by period_start desc) as previous_month - from + lag(unblended_cost_amount, -1) over(partition by service order by period_start desc) as previous_month + from aws_cost_by_service_monthly ) select @@ -189,10 +192,10 @@ select period_start, this_month::numeric::money, previous_month::numeric::money, - case + case when previous_month = 0 and this_month = 0 then 0 when previous_month = 0 then 999 - else round((100 * ( (this_month - previous_month) / previous_month))::numeric, 2) + else round((100 * ( (this_month - previous_month) / previous_month))::numeric, 2) end as percent_change from cost_data @@ -207,8 +210,8 @@ with cost_data as ( service, period_start, unblended_cost_amount as this_month, - lag(unblended_cost_amount,-1) over(partition by service order by period_start desc) as previous_month - from + lag(unblended_cost_amount, -1) over(partition by service order by period_start desc) as previous_month + from aws_cost_by_service_monthly ) select @@ -216,14 +219,49 @@ select period_start, this_month, previous_month, - case + case when previous_month = 0 and this_month = 0 then 0 when previous_month = 0 then 999 - else round((100 * ( (this_month - previous_month) / previous_month)), 2) + else round((100 * ( (this_month - previous_month) / previous_month)), 2) end as percent_change from cost_data order by service, period_start; +``` + +### Get only monthly blended and unblended cost details for the services within a custom time frame +Focusing on blended and unblended costs within a custom time frame offers a clear, detailed perspective on where money is being spent in the cloud, enabling more strategic financial planning and better resource allocation. + +```sql+postgres +select + service, + period_start, + blended_cost_amount::numeric::money, + unblended_cost_amount::numeric::money +from + aws_cost_by_service_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + service, + period_start; +``` + +```sql+sqlite +select + service, + period_start, + cast(blended_cost_amount as decimal), + cast(unblended_cost_amount as decimal) +from + aws_cost_by_service_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +order by + service, + period_start; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_by_service_usage_type_daily.md b/docs/tables/aws_cost_by_service_usage_type_daily.md index 78b5e3728..355253137 100644 --- a/docs/tables/aws_cost_by_service_usage_type_daily.md +++ b/docs/tables/aws_cost_by_service_usage_type_daily.md @@ -11,10 +11,13 @@ The AWS Cost Explorer Service usage type daily is a feature of AWS Cost Manageme The `aws_cost_by_service_usage_type_daily` table in Steampipe provides you with information about daily usage type and costs for each AWS service within AWS Cost Explorer. This table allows you, as a DevOps engineer, financial analyst, or cloud architect, to query daily-specific details, including usage amount, usage unit, and the corresponding service cost. You can utilize this table to gather insights on daily usage and costs, such as identifying high-cost services, tracking usage patterns, and managing your AWS expenses. The schema outlines the various attributes of the AWS service cost, including the service name, usage type, usage amount, usage start and end dates, and the unblended cost. -Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_usage_type_daily` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by day, for the last year. +Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_usage_type_daily` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by day, for the last year. **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -31,7 +34,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_service_usage_type_daily order by service, @@ -48,7 +51,7 @@ select CAST(amortized_cost_amount AS NUMERIC) AS amortized_cost_amount, CAST(net_unblended_cost_amount AS NUMERIC) AS net_unblended_cost_amount, CAST(net_amortized_cost_amount AS NUMERIC) AS net_amortized_cost_amount -from +from aws_cost_by_service_usage_type_daily order by service, @@ -67,7 +70,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_usage_type_daily group by service, @@ -84,7 +87,7 @@ select min(unblended_cost_amount) as min, max(unblended_cost_amount) as max, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_usage_type_daily group by service, @@ -103,7 +106,7 @@ select usage_type, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_usage_type_daily group by service, @@ -119,7 +122,7 @@ select usage_type, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_usage_type_daily group by service, @@ -139,7 +142,7 @@ select usage_type, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_usage_type_daily group by service, @@ -155,7 +158,7 @@ select usage_type, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_usage_type_daily group by service, @@ -163,4 +166,47 @@ group by order by sum desc limit 10; +``` + +### Min, Max, and average daily blended_cost_amount by service and usage type for a specific time range +Gain insights into your AWS service usage by evaluating the minimum, maximum, and average monthly blended costs associated with each service and usage type. + +```sql+postgres +select + service, + usage_type, + min(blended_cost_amount)::numeric::money as min, + max(blended_cost_amount)::numeric::money as max, + avg(blended_cost_amount)::numeric::money as average +from + aws_cost_by_service_usage_type_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +group by + service, + usage_type +order by + service, + usage_type; +``` + +```sql+sqlite +select + service, + usage_type, + min(cast(blended_cost_amount as numeric)) as min, + max(cast(blended_cost_amount as numeric)) as max, + avg(cast(blended_cost_amount as numeric)) as average +from + aws_cost_by_service_usage_type_daily +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +group by + service, + usage_type +order by + service, + usage_type; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_by_service_usage_type_monthly.md b/docs/tables/aws_cost_by_service_usage_type_monthly.md index 4b49bf3df..ef90ce751 100644 --- a/docs/tables/aws_cost_by_service_usage_type_monthly.md +++ b/docs/tables/aws_cost_by_service_usage_type_monthly.md @@ -11,10 +11,13 @@ The AWS Cost Explorer Service is a tool that enables you to view and analyze you The `aws_cost_by_service_usage_type_monthly` table in Steampipe provides you with information about the monthly cost data per service and usage type within AWS Cost Explorer Service. This table allows you, as a financial analyst or cloud cost manager, to query detailed cost data, including the service name, usage type, cost, and currency. You can utilize this table to gather insights on monthly AWS costs, such as cost per service, cost per usage type, and the total monthly cost. The schema outlines the various attributes of the cost data, including the service name, usage type, cost, and the currency used. -Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_usage_type_monthly` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by month, for the last year. +Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs and usage. The `aws_cost_by_service_usage_type_monthly` table provides you with a simplified view of cost for services in your account (or all linked accounts when run against the organization master), summarized by month, for the last year. **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -31,7 +34,7 @@ select amortized_cost_amount::numeric::money, net_unblended_cost_amount::numeric::money, net_amortized_cost_amount::numeric::money -from +from aws_cost_by_service_usage_type_monthly order by service, @@ -48,7 +51,7 @@ select cast(amortized_cost_amount as decimal), cast(net_unblended_cost_amount as decimal), cast(net_amortized_cost_amount as decimal) -from +from aws_cost_by_service_usage_type_monthly order by service, @@ -65,7 +68,7 @@ select min(unblended_cost_amount)::numeric::money as min, max(unblended_cost_amount)::numeric::money as max, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_usage_type_monthly group by service, @@ -82,7 +85,7 @@ select min(cast(unblended_cost_amount as numeric)) as min, max(cast(unblended_cost_amount as numeric)) as max, avg(cast(unblended_cost_amount as numeric)) as average -from +from aws_cost_by_service_usage_type_monthly group by service, @@ -101,7 +104,7 @@ select usage_type, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_usage_type_monthly group by service, @@ -117,7 +120,7 @@ select usage_type, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_usage_type_monthly group by service, @@ -136,7 +139,7 @@ select usage_type, sum(unblended_cost_amount)::numeric::money as sum, avg(unblended_cost_amount)::numeric::money as average -from +from aws_cost_by_service_usage_type_monthly group by service, @@ -152,7 +155,7 @@ select usage_type, sum(unblended_cost_amount) as sum, avg(unblended_cost_amount) as average -from +from aws_cost_by_service_usage_type_monthly group by service, @@ -160,4 +163,47 @@ group by order by sum desc limit 10; +``` + +### Min, Max, and average monthly blended_cost_amount by service and usage type for a specific time range +Gain insights into your AWS service usage by evaluating the minimum, maximum, and average monthly blended costs associated with each service and usage type. + +```sql+postgres +select + service, + usage_type, + min(blended_cost_amount)::numeric::money as min, + max(blended_cost_amount)::numeric::money as max, + avg(blended_cost_amount)::numeric::money as average +from + aws_cost_by_service_usage_type_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +group by + service, + usage_type +order by + service, + usage_type; +``` + +```sql+sqlite +select + service, + usage_type, + min(cast(blended_cost_amount as numeric)) as min, + max(cast(blended_cost_amount as numeric)) as max, + avg(cast(blended_cost_amount as numeric)) as average +from + aws_cost_by_service_usage_type_monthly +where + period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +group by + service, + usage_type +order by + service, + usage_type; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_by_tag.md b/docs/tables/aws_cost_by_tag.md index 9cd484a16..b14e0965b 100644 --- a/docs/tables/aws_cost_by_tag.md +++ b/docs/tables/aws_cost_by_tag.md @@ -16,6 +16,9 @@ Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -125,4 +128,40 @@ where ```sql+sqlite Error: SQLite does not support the rank window function. -``` \ No newline at end of file +``` + +### Get only blended cost and usage details within a custom time frame +This query is useful for organizations to get only blended cost and usage, within a specified time frame, and on a daily granularity. + +```sql+postgres +select + tag_key_1, + tag_value_1, + period_start, + blended_cost_amount::numeric::money +from + aws_cost_by_tag +where + granularity = 'DAILY' + and period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +and + tag_key_1 = 'Name'; +``` + +```sql+sqlite +select + tag_key_1, + tag_value_1, + period_start, + cast(blended_cost_amount as numeric) as blended_cost_amount +from + aws_cost_by_tag +where + granularity = 'DAILY' + and period_start = '2023-05-01T05:30:00+05:30' + and period_end = '2023-05-05T05:30:00+05:30' +and + tag_key_1 = 'Name'; +``` + diff --git a/docs/tables/aws_cost_forecast_daily.md b/docs/tables/aws_cost_forecast_daily.md index 2302f909c..d7afcff93 100644 --- a/docs/tables/aws_cost_forecast_daily.md +++ b/docs/tables/aws_cost_forecast_daily.md @@ -15,6 +15,9 @@ Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -23,23 +26,54 @@ Explore the daily cost forecast for AWS, allowing you to understand and predict ```sql+postgres -select +select period_start, period_end, - mean_value::numeric::money -from + mean_value::numeric::money +from aws_cost_forecast_daily order by period_start; ``` ```sql+sqlite -select +select period_start, period_end, - cast(mean_value as decimal) as mean_value -from + cast(mean_value as decimal) as mean_value +from aws_cost_forecast_daily order by period_start; +``` + +### Get forecast cost and usage details within a custom time frame +This query is useful for organizations to get a forecast, within a specified time frame, and on a daily granularity. + +```sql+postgres +select + period_start, + period_end, + mean_value::numeric::money +from + aws_cost_forecast_daily +where + period_start = '2024-05-01T05:30:00+05:30' + and period_end = '2024-05-05T05:30:00+05:30' +order by + period_start; +``` + +```sql+sqlite +select + period_start, + period_end, + cast(mean_value as real) as mean_value +from + aws_cost_forecast_daily +where + period_start = '2024-05-01T05:30:00+05:30' + and period_end = '2024-05-05T05:30:00+05:30' +order by + period_start; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_forecast_monthly.md b/docs/tables/aws_cost_forecast_monthly.md index 56e324ff0..c5364cfd5 100644 --- a/docs/tables/aws_cost_forecast_monthly.md +++ b/docs/tables/aws_cost_forecast_monthly.md @@ -16,6 +16,9 @@ Amazon Cost Explorer helps you visualize, understand, and manage your AWS costs **Important Notes** - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request you make will incur a cost of $0.01. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -24,30 +27,28 @@ Assess the elements within your AWS cost forecast on a monthly basis to better u ```sql+postgres -select +select period_start, period_end, - mean_value::numeric::money -from + mean_value::numeric::money +from aws_cost_forecast_monthly order by period_start; ``` ```sql+sqlite -select +select period_start, period_end, cast(mean_value as real) as mean_value -from +from aws_cost_forecast_monthly order by period_start; ``` - - ### Month on month forecasted growth Gain insights into the monthly growth forecast by comparing the current month's mean value with the previous month's. This allows for a clear understanding of the growth percentage change, which can aid in future planning and budgeting. @@ -57,17 +58,17 @@ with cost_data as ( period_start, mean_value as this_month, lag(mean_value,-1) over(order by period_start desc) as previous_month - from + from aws_cost_forecast_monthly ) select period_start, this_month::numeric::money, previous_month::numeric::money, - case + case when previous_month = 0 and this_month = 0 then 0 when previous_month = 0 then 999 - else round((100 * ( (this_month - previous_month) / previous_month))::numeric, 2) + else round((100 * ( (this_month - previous_month) / previous_month))::numeric, 2) end as percent_change from cost_data @@ -81,20 +82,51 @@ with cost_data as ( period_start, mean_value as this_month, lag(mean_value,-1) over(order by period_start desc) as previous_month - from + from aws_cost_forecast_monthly ) select period_start, this_month, previous_month, - case + case when previous_month = 0 and this_month = 0 then 0 when previous_month = 0 then 999 - else round((100 * ( (this_month - previous_month) / previous_month)), 2) + else round((100 * ( (this_month - previous_month) / previous_month)), 2) end as percent_change from cost_data order by period_start; +``` + +### Get forecast cost and usage details within a custom time frame +This query is useful for organizations to get a forecast, within a specified time frame, and on a monthly granularity. + +```sql+postgres +select + period_start, + period_end, + mean_value::numeric::money +from + aws_cost_forecast_monthly +where + period_start = '2024-05-01T05:30:00+05:30' + and period_end = '2024-05-05T05:30:00+05:30' +order by + period_start; +``` + +```sql+sqlite +select + period_start, + period_end, + cast(mean_value as real) as mean_value +from + aws_cost_forecast_monthly +where + period_start = '2024-05-01T05:30:00+05:30' + and period_end = '2024-05-05T05:30:00+05:30' +order by + period_start; ``` \ No newline at end of file diff --git a/docs/tables/aws_cost_usage.md b/docs/tables/aws_cost_usage.md index 814611ae7..3320e1562 100644 --- a/docs/tables/aws_cost_usage.md +++ b/docs/tables/aws_cost_usage.md @@ -14,8 +14,12 @@ The `aws_cost_usage` table in Steampipe provides you with information about cost Amazon Cost Explorer assists you in visualizing, understanding, and managing your AWS costs and usage. The `aws_cost_usage` table offers you a simplified yet flexible view of cost for your account (or all linked accounts when run against the organization master). You need to specify a granularity (`MONTHLY`, `DAILY`), and 2 dimension types (`AZ` , `INSTANCE_TYPE`, `LEGAL_ENTITY_NAME`, `LINKED_ACCOUNT`, `OPERATION`, `PLATFORM`, `PURCHASE_TYPE`, `SERVICE`, `TENANCY`, `RECORD_TYPE`, and `USAGE_TYPE`) **Important Notes** + - This table requires an '=' qualifier for all of the following columns: granularity, dimension_type_1, dimension_type_2. - The [pricing for the Cost Explorer API](https://aws.amazon.com/aws-cost-management/pricing/) is per API request - Each request will incur a cost of $0.01 for you. +- This table supports optional quals. Queries with optional quals are optimised to reduce query time and cost. Optional quals are supported for the following columns: + - `period_start` with supported operators `=`, `>=`, `>`, `<=`, and `<`. + - `period_end` with supported operators `=`, `>=`, `>`, `<=`, and `<`. ## Examples @@ -56,6 +60,49 @@ order by period_start; ``` +### Get unblended cost and usage details within a custom time frame +This query is useful for organizations looking to gain a detailed understanding of their AWS costs on a per-service and per-account basis, within a specified time frame, and on a monthly granularity. + +```sql+postgres +select + period_start, + period_end, + dimension_1 as account_id, + dimension_2 as service_name, + net_unblended_cost_amount::numeric::money +from + aws_cost_usage +where + granularity = 'MONTHLY' + and dimension_type_1 = 'LINKED_ACCOUNT' + and dimension_type_2 = 'SERVICE' + and period_start = '2023-04-01T05:30:00+05:30' + and period_end = '2023-04-05T05:30:00+05:30' +order by + dimension_1, + period_start; +``` + +```sql+sqlite +select + period_start, + period_end, + dimension_1 as account_id, + dimension_2 as service_name, + net_unblended_cost_amount::numeric::money +from + aws_cost_usage +where + granularity = 'MONTHLY' + and dimension_type_1 = 'LINKED_ACCOUNT' + and dimension_type_2 = 'SERVICE' + and period_start = '2023-04-01T05:30:00+05:30' + and period_end = '2023-04-05T05:30:00+05:30' +order by + dimension_1, + period_start; +``` + ### Top 5 most expensive services (net unblended cost) in each account Identify the top five most costly services in each account to manage and optimize your AWS expenses effectively. @@ -83,7 +130,26 @@ select * from ranked_costs where rank <=5 ``` ```sql+sqlite -Error: SQLite does not support rank window functions. +with ranked_costs as ( + select + dimension_1 as account_id, + dimension_2 as service_name, + cast(sum(net_unblended_cost_amount) as numeric) as net_unblended_cost, + rank() over ( + partition by dimension_1 + order by sum(net_unblended_cost_amount) desc + ) + from + aws_cost_usage + where + granularity = 'MONTHLY' + and dimension_type_1 = 'LINKED_ACCOUNT' + and dimension_type_2 = 'SERVICE' + group by + dimension_1, + dimension_2 +) +select * from ranked_costs where rank <=5 ``` ### Monthly net unblended cost by account and record type @@ -160,4 +226,4 @@ where order by dimension_1, period_start; -``` \ No newline at end of file +```