Skip to content

Commit 2f33a0e

Browse files
update resource association logic to try both with and without dimension fixes (#1665)
Signed-off-by: Tristan Burgess <[email protected]>
1 parent 5d9a043 commit 2f33a0e

File tree

2 files changed

+85
-33
lines changed

2 files changed

+85
-33
lines changed

Diff for: pkg/job/maxdimassociator/associator.go

+63-32
Original file line numberDiff line numberDiff line change
@@ -174,21 +174,42 @@ func (assoc Associator) AssociateMetricToResource(cwMetric *model.Metric) (*mode
174174

175175
// A regex mapping has been found. The metric has all (and possibly more)
176176
// the dimensions computed for the mapping. Now compute a signature
177-
// of the labels (names and values) of the dimensions of this mapping.
177+
// of the labels (names and values) of the dimensions of this mapping, and try to
178+
// find a resource match.
179+
// This loop can run up to two times:
180+
// On the first iteration, special-case dimension value
181+
// fixes to match the value up with the resource ARN are applied to particular namespaces.
182+
// The second iteration will only run if a fix was applied for one of the special-case
183+
// namespaces and no match was found. It will try to find a match without applying the fixes.
184+
// This covers cases where the dimension value does line up with the resource ARN.
178185
mappingFound = true
179-
labels := buildLabelsMap(cwMetric, regexpMapping)
180-
signature := prom_model.LabelsToSignature(labels)
186+
dimFixApplied := false
187+
shouldTryFixDimension := true
188+
for {
189+
if !dimFixApplied && !shouldTryFixDimension {
190+
// If no dimension fixes were applied, no need to try running again without the fixer
191+
break
192+
}
193+
194+
var labels map[string]string
195+
labels, dimFixApplied = buildLabelsMap(cwMetric, regexpMapping, shouldTryFixDimension)
196+
signature := prom_model.LabelsToSignature(labels)
197+
198+
// Check if there's an entry for the labels (names and values) of the metric,
199+
// and return the resource in case.
200+
if resource, ok := regexpMapping.dimensionsMapping[signature]; ok {
201+
logger.Debug("resource matched", "signature", signature)
202+
return resource, false
203+
}
181204

182-
// Check if there's an entry for the labels (names and values) of the metric,
183-
// and return the resource in case.
184-
if resource, ok := regexpMapping.dimensionsMapping[signature]; ok {
185-
logger.Debug("resource matched", "signature", signature)
186-
return resource, false
205+
// No resource was matched for the current signature.
206+
logger.Debug("resource signature attempt not matched", "signature", signature)
207+
shouldTryFixDimension = false
187208
}
188209

189-
// Otherwise, continue iterating across the rest of regex mappings
190-
// to attempt to find another one with fewer dimensions.
191-
logger.Debug("resource not matched", "signature", signature)
210+
// No resource was matched for any signature, continue iterating across the
211+
// rest of regex mappings to attempt to find another one with fewer dimensions.
212+
logger.Debug("resource not matched")
192213
}
193214
}
194215

@@ -204,38 +225,48 @@ func (assoc Associator) AssociateMetricToResource(cwMetric *model.Metric) (*mode
204225
return nil, mappingFound
205226
}
206227

207-
// buildLabelsMap returns a map of labels names and values.
228+
// buildLabelsMap returns a map of labels names and values, as well as whether the dimension fixer was applied.
208229
// For some namespaces, values might need to be modified in order
209230
// to match the dimension value extracted from ARN.
210-
func buildLabelsMap(cwMetric *model.Metric, regexpMapping *dimensionsRegexpMapping) map[string]string {
231+
func buildLabelsMap(cwMetric *model.Metric, regexpMapping *dimensionsRegexpMapping, shouldTryFixDimension bool) (map[string]string, bool) {
211232
labels := make(map[string]string, len(cwMetric.Dimensions))
233+
dimFixApplied := false
212234
for _, rDimension := range regexpMapping.dimensions {
213235
for _, mDimension := range cwMetric.Dimensions {
214-
name := mDimension.Name
215-
value := mDimension.Value
216-
217-
// AmazonMQ is special - for active/standby ActiveMQ brokers,
218-
// the value of the "Broker" dimension contains a number suffix
219-
// that is not part of the resource ARN
220-
if cwMetric.Namespace == "AWS/AmazonMQ" && name == "Broker" {
221-
if amazonMQBrokerSuffix.MatchString(value) {
222-
value = amazonMQBrokerSuffix.ReplaceAllString(value, "")
223-
}
224-
}
225-
226-
// AWS Sagemaker endpoint name may have upper case characters
227-
// Resource ARN is only in lower case, hence transforming
228-
// endpoint name value to be able to match the resource ARN
229-
if cwMetric.Namespace == "AWS/SageMaker" && name == "EndpointName" {
230-
value = strings.ToLower(value)
236+
if shouldTryFixDimension {
237+
mDimension, dimFixApplied = fixDimension(cwMetric.Namespace, mDimension)
231238
}
232239

233240
if rDimension == mDimension.Name {
234-
labels[name] = value
241+
labels[mDimension.Name] = mDimension.Value
235242
}
236243
}
237244
}
238-
return labels
245+
return labels, dimFixApplied
246+
}
247+
248+
// fixDimension modifies the dimension value to accommodate special cases where
249+
// the dimension value doesn't match the resource ARN.
250+
func fixDimension(namespace string, dim model.Dimension) (model.Dimension, bool) {
251+
// AmazonMQ is special - for active/standby ActiveMQ brokers,
252+
// the value of the "Broker" dimension contains a number suffix
253+
// that is not part of the resource ARN
254+
if namespace == "AWS/AmazonMQ" && dim.Name == "Broker" {
255+
if amazonMQBrokerSuffix.MatchString(dim.Value) {
256+
dim.Value = amazonMQBrokerSuffix.ReplaceAllString(dim.Value, "")
257+
return dim, true
258+
}
259+
}
260+
261+
// AWS Sagemaker endpoint name may have upper case characters
262+
// Resource ARN is only in lower case, hence transforming
263+
// endpoint name value to be able to match the resource ARN
264+
if namespace == "AWS/SageMaker" && dim.Name == "EndpointName" {
265+
dim.Value = strings.ToLower(dim.Value)
266+
return dim, true
267+
}
268+
269+
return dim, false
239270
}
240271

241272
// containsAll returns true if a contains all elements of b

Diff for: pkg/job/maxdimassociator/associator_mq_test.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ var rabbitMQBroker = &model.TaggedResource{
2727
Namespace: "AWS/AmazonMQ",
2828
}
2929

30+
var rabbitMQBrokerWithActiveStyleName = &model.TaggedResource{
31+
ARN: "arn:aws:mq:us-east-2:123456789012:broker:rabbitmq-broker-0:b-000-111-222-333",
32+
Namespace: "AWS/AmazonMQ",
33+
}
34+
3035
var activeMQBroker = &model.TaggedResource{
3136
ARN: "arn:aws:mq:us-east-2:123456789012:broker:activemq-broker:b-000-111-222-333",
3237
Namespace: "AWS/AmazonMQ",
@@ -63,11 +68,27 @@ func TestAssociatorMQ(t *testing.T) {
6368
expectedSkip: false,
6469
expectedResource: rabbitMQBroker,
6570
},
71+
{
72+
name: "should match with Broker dimension when broker name has a number suffix and does match ARN",
73+
args: args{
74+
dimensionRegexps: config.SupportedServices.GetService("AWS/AmazonMQ").ToModelDimensionsRegexp(),
75+
resources: []*model.TaggedResource{rabbitMQBrokerWithActiveStyleName},
76+
metric: &model.Metric{
77+
MetricName: "ProducerCount",
78+
Namespace: "AWS/AmazonMQ",
79+
Dimensions: []model.Dimension{
80+
{Name: "Broker", Value: "rabbitmq-broker-0"},
81+
},
82+
},
83+
},
84+
expectedSkip: false,
85+
expectedResource: rabbitMQBrokerWithActiveStyleName,
86+
},
6687
{
6788
// ActiveMQ allows active/standby modes where the `Broker` dimension has values
6889
// like `brokername-1` and `brokername-2` which don't match the ARN (the dimension
6990
// regex will extract `Broker` as `brokername` from ARN)
70-
name: "should match with Broker dimension when broker name has a number suffix",
91+
name: "should match with Broker dimension when broker name has a number suffix and doesn't match ARN",
7192
args: args{
7293
dimensionRegexps: config.SupportedServices.GetService("AWS/AmazonMQ").ToModelDimensionsRegexp(),
7394
resources: []*model.TaggedResource{activeMQBroker},

0 commit comments

Comments
 (0)