CloudWatch: Handle permissions error and update docs (#88524)

This commit is contained in:
Isabella Siu 2024-05-31 14:36:38 -04:00 committed by GitHub
parent 73905695e3
commit be2e420e6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 58 additions and 1 deletions

View File

@ -123,6 +123,12 @@ You can attach these permissions to the IAM role or IAM user you configured in [
"Effect": "Allow", "Effect": "Allow",
"Action": "tag:GetResources", "Action": "tag:GetResources",
"Resource": "*" "Resource": "*"
},
{
"Sid": "AllowReadingResourceMetricsFromPerformanceInsights",
"Effect": "Allow",
"Action": "pi:GetResourceMetrics",
"Resource": "*"
} }
] ]
} }
@ -182,6 +188,12 @@ You can attach these permissions to the IAM role or IAM user you configured in [
], ],
"Resource": "*" "Resource": "*"
}, },
{
"Sid": "AllowReadingResourceMetricsFromPerformanceInsights",
"Effect": "Allow",
"Action": "pi:GetResourceMetrics",
"Resource": "*"
},
{ {
"Sid": "AllowReadingLogsFromCloudWatch", "Sid": "AllowReadingLogsFromCloudWatch",
"Effect": "Allow", "Effect": "Allow",

View File

@ -1,6 +1,8 @@
package models package models
import "github.com/aws/aws-sdk-go/service/cloudwatch" import (
"github.com/aws/aws-sdk-go/service/cloudwatch"
)
// queryRowResponse represents the GetMetricData response for a query row in the query editor. // queryRowResponse represents the GetMetricData response for a query row in the query editor.
type QueryRowResponse struct { type QueryRowResponse struct {
@ -8,6 +10,8 @@ type QueryRowResponse struct {
ErrorCodes map[string]bool ErrorCodes map[string]bool
HasArithmeticError bool HasArithmeticError bool
ArithmeticErrorMessage string ArithmeticErrorMessage string
HasPermissionError bool
PermissionErrorMessage string
Metrics []*cloudwatch.MetricDataResult Metrics []*cloudwatch.MetricDataResult
StatusCode string StatusCode string
} }
@ -23,6 +27,10 @@ func NewQueryRowResponse(errors map[string]bool) QueryRowResponse {
} }
func (q *QueryRowResponse) AddMetricDataResult(mdr *cloudwatch.MetricDataResult) { func (q *QueryRowResponse) AddMetricDataResult(mdr *cloudwatch.MetricDataResult) {
if mdr.Label == nil {
return
}
if partialData, ok := q.partialDataSet[*mdr.Label]; ok { if partialData, ok := q.partialDataSet[*mdr.Label]; ok {
partialData.Timestamps = append(partialData.Timestamps, mdr.Timestamps...) partialData.Timestamps = append(partialData.Timestamps, mdr.Timestamps...)
partialData.Values = append(partialData.Values, mdr.Values...) partialData.Values = append(partialData.Values, mdr.Values...)
@ -44,3 +52,8 @@ func (q *QueryRowResponse) AddArithmeticError(message *string) {
q.HasArithmeticError = true q.HasArithmeticError = true
q.ArithmeticErrorMessage = *message q.ArithmeticErrorMessage = *message
} }
func (q *QueryRowResponse) AddPermissionError(message *string) {
q.HasPermissionError = true
q.PermissionErrorMessage = *message
}

View File

@ -35,6 +35,10 @@ func (e *cloudWatchExecutor) parseResponse(ctx context.Context, startTime time.T
dataRes.Error = fmt.Errorf("ArithmeticError in query %q: %s", queryRow.RefId, response.ArithmeticErrorMessage) dataRes.Error = fmt.Errorf("ArithmeticError in query %q: %s", queryRow.RefId, response.ArithmeticErrorMessage)
} }
if response.HasPermissionError {
dataRes.Error = fmt.Errorf("PermissionError in query %q: %s", queryRow.RefId, response.PermissionErrorMessage)
}
var err error var err error
dataRes.Frames, err = buildDataFrames(ctx, startTime, endTime, response, queryRow) dataRes.Frames, err = buildDataFrames(ctx, startTime, endTime, response, queryRow)
if err != nil { if err != nil {
@ -79,6 +83,9 @@ func aggregateResponse(getMetricDataOutputs []*cloudwatch.GetMetricDataOutput) m
if *message.Code == "ArithmeticError" { if *message.Code == "ArithmeticError" {
response.AddArithmeticError(message.Value) response.AddArithmeticError(message.Value)
} }
if *message.Code == "Forbidden" {
response.AddPermissionError(message.Value)
}
} }
response.AddMetricDataResult(r) response.AddMetricDataResult(r)

View File

@ -135,6 +135,15 @@ func TestCloudWatchResponseParser(t *testing.T) {
}) })
}) })
}) })
t.Run("when receiving a permissions error should pass it to the user", func(t *testing.T) {
getMetricDataOutputs, err := loadGetMetricDataOutputsFromFile("./testdata/permissions-error-output.json")
require.NoError(t, err)
aggregatedResponse := aggregateResponse(getMetricDataOutputs)
assert.True(t, aggregatedResponse["a"].HasPermissionError)
assert.Equal(t, "Access denied when getting data - please check that you have the pi:GetResourceMetrics permission", aggregatedResponse["a"].PermissionErrorMessage)
})
} }
func Test_buildDataFrames_parse_label_to_name_and_labels(t *testing.T) { func Test_buildDataFrames_parse_label_to_name_and_labels(t *testing.T) {

View File

@ -0,0 +1,16 @@
[
{
"Messages": null,
"MetricDataResults": [
{
"Id": "a",
"Messages": [{
"Code": "Forbidden",
"Value": "Access denied when getting data - please check that you have the pi:GetResourceMetrics permission"
}],
"StatusCode": "Forbidden"
}
],
"NextToken": null
}
]