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(autoscaling): throw ValidationError instead of untyped Errors #33388

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/aws-cdk-lib/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ baseConfig.rules['import/no-extraneous-dependencies'] = [

// no-throw-default-error
const enableNoThrowDefaultErrorIn = [
'aws-autoscaling',
'aws-autoscaling-common',
'aws-amplify',
'aws-amplifyuibuilder',
'aws-apigateway',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ScalingInterval } from './types';
import { UnscopedValidationError } from '../../core';

export interface CompleteScalingInterval {
readonly lower: number;
Expand Down Expand Up @@ -30,12 +31,12 @@ export function normalizeIntervals(intervals: ScalingInterval[], changesAreAbsol
*/
function orderAndCompleteIntervals(intervals: ScalingInterval[]): CompleteScalingInterval[] {
if (intervals.length < 2) {
throw new Error('Require at least 2 intervals');
throw new UnscopedValidationError('Require at least 2 intervals');
}

for (const interval of intervals) {
if (interval.lower === undefined && interval.upper === undefined) {
throw new Error(`Must supply at least one of 'upper' or 'lower', got: ${JSON.stringify(interval)}`);
throw new UnscopedValidationError(`Must supply at least one of 'upper' or 'lower', got: ${JSON.stringify(interval)}`);
}
}

Expand All @@ -55,7 +56,7 @@ function orderAndCompleteIntervals(intervals: ScalingInterval[]): CompleteScalin
if (intervals[lastIndex].upper === undefined) { intervals[lastIndex] = { ...intervals[lastIndex], upper: Infinity }; }
for (const interval of intervals) {
if (interval.lower === undefined || interval.upper === undefined) {
throw new Error(`Could not determine the lower and upper bounds for ${JSON.stringify(interval)}`);
throw new UnscopedValidationError(`Could not determine the lower and upper bounds for ${JSON.stringify(interval)}`);
}
}

Expand All @@ -64,7 +65,7 @@ function orderAndCompleteIntervals(intervals: ScalingInterval[]): CompleteScalin
// Validate that we have nonoverlapping intervals now.
for (let i = 0; i < completeIntervals.length - 1; i++) {
if (overlap(completeIntervals[i], completeIntervals[i + 1])) {
throw new Error(`Two intervals overlap: ${JSON.stringify(completeIntervals[i])} and ${JSON.stringify(completeIntervals[i + 1])}`);
throw new UnscopedValidationError(`Two intervals overlap: ${JSON.stringify(completeIntervals[i])} and ${JSON.stringify(completeIntervals[i + 1])}`);
}
}

Expand Down Expand Up @@ -148,7 +149,7 @@ function combineUndefineds(intervals: CompleteScalingInterval[]) {
function validateAtMostOneUndefined(intervals: CompleteScalingInterval[]) {
const undef = intervals.filter(x => x.change === undefined);
if (undef.length > 1) {
throw new Error(`Can have at most one no-change interval, got ${JSON.stringify(undef)}`);
throw new UnscopedValidationError(`Can have at most one no-change interval, got ${JSON.stringify(undef)}`);
}
}

Expand Down
108 changes: 54 additions & 54 deletions packages/aws-cdk-lib/aws-autoscaling/lib/auto-scaling-group.ts

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IAutoScalingGroup } from './auto-scaling-group';
import { CfnLifecycleHook } from './autoscaling.generated';
import { ILifecycleHookTarget } from './lifecycle-hook-target';
import * as iam from '../../aws-iam';
import { Duration, IResource, Resource } from '../../core';
import { Duration, IResource, Resource, ValidationError } from '../../core';
import { addConstructMetadata } from '../../core/lib/metadata-resource';

/**
Expand Down Expand Up @@ -97,7 +97,7 @@ export class LifecycleHook extends Resource implements ILifecycleHook {
*/
public get role() {
if (!this._role) {
throw new Error('\'role\' is undefined. Please specify a \'role\' or specify a \'notificationTarget\' to have a role provided for you.');
throw new ValidationError('\'role\' is undefined. Please specify a \'role\' or specify a \'notificationTarget\' to have a role provided for you.', this);
}

return this._role;
Expand All @@ -122,7 +122,7 @@ export class LifecycleHook extends Resource implements ILifecycleHook {
this._role = props.role;

if (!props.notificationTarget) {
throw new Error("'notificationTarget' parameter required when 'role' parameter is specified");
throw new ValidationError("'notificationTarget' parameter required when 'role' parameter is specified", this);
}
} else {
this._role = targetProps ? targetProps.createdRole : undefined;
Expand Down
4 changes: 2 additions & 2 deletions packages/aws-cdk-lib/aws-autoscaling/lib/schedule.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Construct } from 'constructs';
import { Annotations } from '../../core';
import { Annotations, UnscopedValidationError } from '../../core';

/**
* Schedule for scheduled scaling actions
Expand All @@ -20,7 +20,7 @@ export abstract class Schedule {
*/
public static cron(options: CronOptions): Schedule {
if (options.weekDay !== undefined && options.day !== undefined) {
throw new Error('Cannot supply both \'day\' and \'weekDay\', use at most one');
throw new UnscopedValidationError('Cannot supply both \'day\' and \'weekDay\', use at most one');
}

const minute = fallback(options.minute, '*');
Expand Down
4 changes: 2 additions & 2 deletions packages/aws-cdk-lib/aws-autoscaling/lib/scheduled-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Construct } from 'constructs';
import { IAutoScalingGroup } from './auto-scaling-group';
import { CfnScheduledAction } from './autoscaling.generated';
import { Schedule } from './schedule';
import { Resource } from '../../core';
import { Resource, ValidationError } from '../../core';
import { addConstructMetadata } from '../../core/lib/metadata-resource';

/**
Expand Down Expand Up @@ -104,7 +104,7 @@ export class ScheduledAction extends Resource {
addConstructMetadata(this, props);

if (props.minCapacity === undefined && props.maxCapacity === undefined && props.desiredCapacity === undefined) {
throw new Error('At least one of minCapacity, maxCapacity, or desiredCapacity is required');
throw new ValidationError('At least one of minCapacity, maxCapacity, or desiredCapacity is required', this);
}

// add a warning on synth when minute is not defined in a cron schedule
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Construct } from 'constructs';
import { IAutoScalingGroup } from './auto-scaling-group';
import { CfnScalingPolicy } from './autoscaling.generated';
import { Annotations, Duration, Lazy } from '../../core';
import { Annotations, Duration, Lazy, ValidationError } from '../../core';

/**
* Properties for a scaling policy
Expand Down Expand Up @@ -97,7 +97,7 @@ export class StepScalingAction extends Construct {
*/
public addAdjustment(adjustment: AdjustmentTier) {
if (adjustment.lowerBound === undefined && adjustment.upperBound === undefined) {
throw new Error('At least one of lowerBound or upperBound is required');
throw new ValidationError('At least one of lowerBound or upperBound is required', this);
}
this.adjustments.push({
metricIntervalLowerBound: adjustment.lowerBound,
Expand Down
14 changes: 7 additions & 7 deletions packages/aws-cdk-lib/aws-autoscaling/lib/step-scaling-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IAutoScalingGroup } from './auto-scaling-group';
import { AdjustmentType, MetricAggregationType, StepScalingAction } from './step-scaling-action';
import { findAlarmThresholds, normalizeIntervals } from '../../aws-autoscaling-common';
import * as cloudwatch from '../../aws-cloudwatch';
import { Duration, Token } from '../../core';
import { Duration, Token, ValidationError } from '../../core';

export interface BasicStepScalingPolicyProps {
/**
Expand Down Expand Up @@ -112,28 +112,28 @@ export class StepScalingPolicy extends Construct {
super(scope, id);

if (props.scalingSteps.length < 2) {
throw new Error('You must supply at least 2 intervals for autoscaling');
throw new ValidationError('You must supply at least 2 intervals for autoscaling', this);
}

if (props.scalingSteps.length > 40) {
throw new Error(`'scalingSteps' can have at most 40 steps, got ${props.scalingSteps.length}`);
throw new ValidationError(`'scalingSteps' can have at most 40 steps, got ${props.scalingSteps.length}`, this);
}

if (props.evaluationPeriods !== undefined && !Token.isUnresolved(props.evaluationPeriods) && props.evaluationPeriods < 1) {
throw new Error(`evaluationPeriods cannot be less than 1, got: ${props.evaluationPeriods}`);
throw new ValidationError(`evaluationPeriods cannot be less than 1, got: ${props.evaluationPeriods}`, this);
}
if (props.datapointsToAlarm !== undefined) {
if (props.evaluationPeriods === undefined) {
throw new Error('evaluationPeriods must be set if datapointsToAlarm is set');
throw new ValidationError('evaluationPeriods must be set if datapointsToAlarm is set', this);
}
if (!Token.isUnresolved(props.datapointsToAlarm) && props.datapointsToAlarm < 1) {
throw new Error(`datapointsToAlarm cannot be less than 1, got: ${props.datapointsToAlarm}`);
throw new ValidationError(`datapointsToAlarm cannot be less than 1, got: ${props.datapointsToAlarm}`, this);
}
if (!Token.isUnresolved(props.datapointsToAlarm)
&& !Token.isUnresolved(props.evaluationPeriods)
&& props.evaluationPeriods < props.datapointsToAlarm
) {
throw new Error(`datapointsToAlarm must be less than or equal to evaluationPeriods, got datapointsToAlarm: ${props.datapointsToAlarm}, evaluationPeriods: ${props.evaluationPeriods}`);
throw new ValidationError(`datapointsToAlarm must be less than or equal to evaluationPeriods, got datapointsToAlarm: ${props.datapointsToAlarm}, evaluationPeriods: ${props.evaluationPeriods}`, this);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Construct } from 'constructs';
import { IAutoScalingGroup } from './auto-scaling-group';
import { CfnScalingPolicy } from './autoscaling.generated';
import * as cloudwatch from '../../aws-cloudwatch';
import { Duration } from '../../core';
import { Duration, ValidationError } from '../../core';

/**
* Base interface for target tracking props
Expand Down Expand Up @@ -110,20 +110,20 @@ export class TargetTrackingScalingPolicy extends Construct {
private resource: CfnScalingPolicy;

constructor(scope: Construct, id: string, props: TargetTrackingScalingPolicyProps) {
super(scope, id);

if ((props.customMetric === undefined) === (props.predefinedMetric === undefined)) {
throw new Error('Exactly one of \'customMetric\' or \'predefinedMetric\' must be specified.');
throw new ValidationError('Exactly one of \'customMetric\' or \'predefinedMetric\' must be specified.', this);
}

if (props.predefinedMetric === PredefinedMetric.ALB_REQUEST_COUNT_PER_TARGET && !props.resourceLabel) {
throw new Error('When tracking the ALBRequestCountPerTarget metric, the ALB identifier must be supplied in resourceLabel');
throw new ValidationError('When tracking the ALBRequestCountPerTarget metric, the ALB identifier must be supplied in resourceLabel', this);
}

if (props.customMetric && !props.customMetric.toMetricConfig().metricStat) {
throw new Error('Only direct metrics are supported for Target Tracking. Use Step Scaling or supply a Metric object.');
throw new ValidationError('Only direct metrics are supported for Target Tracking. Use Step Scaling or supply a Metric object.', this);
}

super(scope, id);

this.resource = new CfnScalingPolicy(this, 'Resource', {
policyType: 'TargetTrackingScaling',
autoScalingGroupName: props.autoScalingGroup.autoScalingGroupName,
Expand Down
4 changes: 3 additions & 1 deletion packages/aws-cdk-lib/aws-autoscaling/lib/volume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// existed first in the "autoscaling" module before it existed in the "ec2"
// module so we couldn't standardize the structs in the right way.

import { UnscopedValidationError } from '../../core';

/**
* Block device
*/
Expand Down Expand Up @@ -154,7 +156,7 @@ export class BlockDeviceVolume {
*/
public static ephemeral(volumeIndex: number) {
if (volumeIndex < 0) {
throw new Error(`volumeIndex must be a number starting from 0, got "${volumeIndex}"`);
throw new UnscopedValidationError(`volumeIndex must be a number starting from 0, got "${volumeIndex}"`);
}

return new this(undefined, `ephemeral${volumeIndex}`);
Expand Down
6 changes: 3 additions & 3 deletions packages/aws-cdk-lib/aws-autoscaling/lib/warm-pool.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Construct } from 'constructs';
import { IAutoScalingGroup } from './auto-scaling-group';
import { CfnWarmPool } from './autoscaling.generated';
import { Lazy, Names, Resource } from '../../core';
import { Lazy, Names, Resource, ValidationError } from '../../core';
import { addConstructMetadata } from '../../core/lib/metadata-resource';

/**
Expand Down Expand Up @@ -64,11 +64,11 @@ export class WarmPool extends Resource {
addConstructMetadata(this, props);

if (props.maxGroupPreparedCapacity && props.maxGroupPreparedCapacity < -1) {
throw new Error('\'maxGroupPreparedCapacity\' parameter should be greater than or equal to -1');
throw new ValidationError('\'maxGroupPreparedCapacity\' parameter should be greater than or equal to -1', this);
}

if (props.minSize && props.minSize < 0) {
throw new Error('\'minSize\' parameter should be greater than or equal to 0');
throw new ValidationError('\'minSize\' parameter should be greater than or equal to 0', this);
}

new CfnWarmPool(this, 'Resource', {
Expand Down
Loading