Skip to content

Commit

Permalink
feat(elbv2): support pathpattern array (#6558)
Browse files Browse the repository at this point in the history
* Adding support for an array of path patterns for application listener rule config.

Closes #6497

* Introduce `pathPatterns` prop for listener rule

* Introduce `pathPatterns` prop for listener rule

* Deperecate `pathPattern`.

Co-authored-by: Derk Schooltink <[email protected]>
Co-authored-by: Rico Huijbers <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Mar 9, 2020
1 parent 05cf78b commit c3ee413
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 18 deletions.
17 changes: 11 additions & 6 deletions packages/@aws-cdk/aws-elasticloadbalancingv2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,28 @@ listener.addFixedResponse('Fixed', {
#### Conditions

It's possible to route traffic to targets based on conditions in the incoming
HTTP request. Path- and host-based conditions are supported. For example,
the following will route requests to the indicated AutoScalingGroup
only if the requested host in the request is `example.com`:
HTTP request. Path- and host-based conditions are supported. For example, the
following will route requests to the indicated AutoScalingGroup only if the
requested host in the request is either for `example.com/ok` or
`example.com/path`:

```ts
listener.addTargets('Example.Com Fleet', {
priority: 10,
pathPatterns: ['/ok', '/path'],
hostHeader: 'example.com',
port: 8080,
targets: [asg]
});
```

`priority` is a required field when you add targets with conditions. The lowest
number wins.
A target with a condition contains either `pathPatterns` or `hostHeader`, or
both. If both are specified, both conditions must be met for the requests to
be routed to the given target. `priority` is a required field when you add
targets with conditions. The lowest number wins.

Every listener must have at least one target without conditions.
Every listener must have at least one target without conditions, which is
where all requests that didn't match any of the conditions will be sent.

### Defining a Network Load Balancer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,21 @@ export interface BaseApplicationListenerRuleProps {
/**
* Rule applies if the requested path matches the given path pattern
*
* May contain up to three '*' wildcards.
*
* @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#path-conditions
*
* @default - No path condition.
* @deprecated Use `pathPatterns` instead.
*/
readonly pathPattern?: string;

/**
* Rule applies if the requested path matches any of the given patterns.
*
* Paths may contain up to three '*' wildcards.
*
* @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#path-conditions
* @default - No path conditions.
*/
readonly pathPatterns?: string[];
}

/**
Expand Down Expand Up @@ -169,8 +177,9 @@ export class ApplicationListenerRule extends cdk.Construct {
constructor(scope: cdk.Construct, id: string, props: ApplicationListenerRuleProps) {
super(scope, id);

if (!props.hostHeader && !props.pathPattern) {
throw new Error(`At least one of 'hostHeader' or 'pathPattern' is required when defining a load balancing rule.`);
const hasPathPatterns = props.pathPatterns || props.pathPattern;
if (!props.hostHeader && !hasPathPatterns) {
throw new Error(`At least one of 'hostHeader', 'pathPattern' or 'pathPatterns' is required when defining a load balancing rule.`);
}

const possibleActions: Array<keyof ApplicationListenerRuleProps> = ['targetGroups', 'fixedResponse', 'redirectResponse'];
Expand All @@ -195,8 +204,13 @@ export class ApplicationListenerRule extends cdk.Construct {
if (props.hostHeader) {
this.setCondition('host-header', [props.hostHeader]);
}
if (props.pathPattern) {
this.setCondition('path-pattern', [props.pathPattern]);

if (hasPathPatterns) {
if (props.pathPattern && props.pathPatterns) {
throw new Error('Both `pathPatterns` and `pathPattern` are specified, specify only one');
}
const pathPattern = props.pathPattern ? [props.pathPattern] : props.pathPatterns;
this.setCondition('path-pattern', pathPattern);
}

(props.targetGroups || []).forEach(this.addTargetGroup.bind(this));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export class ApplicationListener extends BaseListener implements IApplicationLis
listener: this,
hostHeader: props.hostHeader,
pathPattern: props.pathPattern,
pathPatterns: props.pathPatterns,
priority: props.priority,
targetGroups: props.targetGroups
});
Expand Down Expand Up @@ -252,6 +253,7 @@ export class ApplicationListener extends BaseListener implements IApplicationLis
this.addTargetGroups(id, {
hostHeader: props.hostHeader,
pathPattern: props.pathPattern,
pathPatterns: props.pathPatterns,
priority: props.priority,
targetGroups: [group],
});
Expand Down Expand Up @@ -480,9 +482,7 @@ class ImportedApplicationListener extends Resource implements IApplicationListen
* At least one TargetGroup must be added without conditions.
*/
public addTargetGroups(id: string, props: AddApplicationTargetGroupsProps): void {
if ((props.hostHeader !== undefined || props.pathPattern !== undefined) !== (props.priority !== undefined)) {
throw new Error(`Setting 'pathPattern' or 'hostHeader' also requires 'priority', and vice versa`);
}
checkAddRuleProps(props);

if (props.priority !== undefined) {
// New rule
Expand Down Expand Up @@ -562,10 +562,22 @@ export interface AddRuleProps {
* Requires that priority is set.
*
* @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#path-conditions
*
* @default No path condition
* @deprecated Use `pathPatterns` instead.
*/
readonly pathPattern?: string;

/**
* Rule applies if the requested path matches any of the given patterns.
*
* May contain up to three '*' wildcards.
*
* Requires that priority is set.
*
* @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#path-conditions
* @default - No path condition.
*/
readonly pathPatterns?: string[];
}

/**
Expand Down Expand Up @@ -667,7 +679,7 @@ export interface AddRedirectResponseProps extends AddRuleProps, RedirectResponse
}

function checkAddRuleProps(props: AddRuleProps) {
if ((props.hostHeader !== undefined || props.pathPattern !== undefined) !== (props.priority !== undefined)) {
if ((props.hostHeader !== undefined || props.pathPattern !== undefined || props.pathPatterns !== undefined) !== (props.priority !== undefined)) {
throw new Error(`Setting 'pathPattern' or 'hostHeader' also requires 'priority', and vice versa`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,61 @@ export = {

test.done();
},

'Can add multiple path patterns to listener rule'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'Stack');
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc });

// WHEN
const listener = lb.addListener('Listener', {
port: 443,
certificateArns: ['cert1', 'cert2'],
defaultTargetGroups: [new elbv2.ApplicationTargetGroup(stack, 'Group', { vpc, port: 80 })]
});

listener.addTargets('Target1', {
priority: 10,
pathPatterns: ['/test/path/1', '/test/path/2']
});

// THEN
expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::ListenerRule', {
Priority: 10,
Conditions: [
{
Field: 'path-pattern',
Values: ['/test/path/1', '/test/path/2']
}
]
}));

test.done();
},

'Cannot add pathPattern and pathPatterns to listener rule'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'Stack');
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc });

// WHEN
const listener = lb.addListener('Listener', {
port: 443,
certificateArns: ['cert1', 'cert2'],
defaultTargetGroups: [new elbv2.ApplicationTargetGroup(stack, 'Group', { vpc, port: 80 })]
});

// THEN
test.throws(() => listener.addTargets('Target1', {
priority: 10,
pathPatterns: ['/test/path/1', '/test/path/2'],
pathPattern: '/test/path/3'
}), Error, `At least one of 'hostHeader', 'pathPattern' or 'pathPatterns' is required when defining a load balancing rule.`);

test.done();
},
};

class ResourceWithLBDependency extends cdk.CfnResource {
Expand Down

0 comments on commit c3ee413

Please sign in to comment.