Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(cloudwatch): validate parameters for a metric dimensions (closes #3116) #14365

Merged
merged 7 commits into from
May 7, 2021
6 changes: 4 additions & 2 deletions packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,23 @@ export interface IMetric {
/**
* Turn this metric object into an alarm configuration
*
* @deprecated Use `toMetricsConfig()` instead.
* @deprecated Use `toMetricConfig()` instead.
*/
toAlarmConfig(): MetricAlarmConfig;

/**
* Turn this metric object into a graph configuration
*
* @deprecated Use `toMetricsConfig()` instead.
* @deprecated Use `toMetricConfig()` instead.
*/
toGraphConfig(): MetricGraphConfig;
}

/**
* Metric dimension
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-dimension.html
*
*/
export interface Dimension {
/**
Expand Down
24 changes: 23 additions & 1 deletion packages/@aws-cdk/aws-cloudwatch/lib/metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,9 @@ export class Metric implements IMetric {
if (periodSec !== 1 && periodSec !== 5 && periodSec !== 10 && periodSec !== 30 && periodSec % 60 !== 0) {
throw new Error(`'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received ${periodSec}`);
}

if (props.dimensions) {
this.validateDimensions(props.dimensions);
}
this.dimensions = props.dimensions;
this.namespace = props.namespace;
this.metricName = props.metricName;
Expand Down Expand Up @@ -395,6 +397,26 @@ export class Metric implements IMetric {

return list;
}

private validateDimensions(dims: DimensionHash): void {
var dimsArray = Object.keys(dims);
if (dimsArray?.length > 10) {
throw new Error(`The maximum number of dimensions is 10, received ${dimsArray.length}`);
}

dimsArray.map(key => {
if (dims[key] === undefined || dims[key] === null) {
throw new Error(`Dimension value of '${dims[key]}' is invalid`);
};
if (key.length < 1 || key.length > 255) {
throw new Error(`Dimension name must be at least 1 and no more than 255 characters; received ${key}`);
};

if (dims[key].length < 1 || dims[key].length > 255) {
throw new Error(`Dimension value must be at least 1 and no more than 255 characters; received ${dims[key]}`);
};
});
}
}

function asString(x?: unknown): string | undefined {
Expand Down
73 changes: 73 additions & 0 deletions packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,77 @@ export = {

test.done();
},

'cannot use null dimension value'(test: Test) {
test.throws(() => {
new Metric({
namespace: 'Test',
metricName: 'ACount',
period: cdk.Duration.minutes(10),
dimensions: {
DimensionWithNull: null,
},
});
}, /Dimension value of 'null' is invalid/);

test.done();
},

'cannot use undefined dimension value'(test: Test) {
test.throws(() => {
new Metric({
namespace: 'Test',
metricName: 'ACount',
period: cdk.Duration.minutes(10),
dimensions: {
DimensionWithUndefined: undefined,
},
});
}, /Dimension value of 'undefined' is invalid/);

test.done();
},

'cannot use long dimension values'(test: Test) {
const arr = new Array(256);
const invalidDimensionValue = arr.fill('A', 0).join('');

test.throws(() => {
new Metric({
namespace: 'Test',
metricName: 'ACount',
period: cdk.Duration.minutes(10),
dimensions: {
DimensionWithLongValue: invalidDimensionValue,
},
});
}, `Dimension value must be at least 1 and no more than 255 characters; received ${invalidDimensionValue}`);

test.done();
},

'throws error when there are more than 10 dimensions'(test: Test) {
test.throws(() => {
new Metric({
namespace: 'Test',
metricName: 'ACount',
period: cdk.Duration.minutes(10),
dimensions: {
dimensionA: 'value1',
dimensionB: 'value2',
dimensionC: 'value3',
dimensionD: 'value4',
dimensionE: 'value5',
dimensionF: 'value6',
dimensionG: 'value7',
dimensionH: 'value8',
dimensionI: 'value9',
dimensionJ: 'value10',
dimensionK: 'value11',
},
} );
}, /The maximum number of dimensions is 10, received 11/);

test.done();
},
};