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(appmesh): change VirtualRouter's Listener to a union-like class #11277

Merged
merged 17 commits into from
Nov 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,9 @@ export class AppMeshExtension extends ServiceExtension {
// and other similar behaviors.
this.virtualRouter = new appmesh.VirtualRouter(this.scope, `${this.parentService.id}-virtual-router`, {
mesh: this.mesh,
listener: {
portMapping: {
port: containerextension.trafficPort,
protocol: this.protocol,
},
},
listeners: [
this.virtualRouterListener(containerextension.trafficPort),
],
virtualRouterName: `${this.parentService.id}`,
});

Expand Down Expand Up @@ -331,4 +328,13 @@ export class AppMeshExtension extends ServiceExtension {
// nodes from the other service.
this.virtualNode.addBackends(otherAppMesh.virtualService);
}

private virtualRouterListener(port: number): appmesh.VirtualRouterListener {
switch (this.protocol) {
case appmesh.Protocol.HTTP: return appmesh.VirtualRouterListener.http(port);
case appmesh.Protocol.HTTP2: return appmesh.VirtualRouterListener.http2(port);
case appmesh.Protocol.GRPC: return appmesh.VirtualRouterListener.grpc(port);
case appmesh.Protocol.TCP: return appmesh.VirtualRouterListener.tcp(port);
}
}
}
30 changes: 13 additions & 17 deletions packages/@aws-cdk/aws-appmesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,21 @@ const mesh = new Mesh(stack, 'AppMesh', {

## Adding VirtualRouters

The `Mesh` needs `VirtualRouters` as logical units to route to `VirtualNodes`.
The _Mesh_ needs _VirtualRouters_ as logical units to route requests to _VirtualNodes_.

Virtual routers handle traffic for one or more virtual services within your mesh. After you create a virtual router, you can create and associate routes for your virtual router that direct incoming requests to different virtual nodes.
Virtual routers handle traffic for one or more virtual services within your mesh.
After you create a virtual router, you can create and associate routes to your virtual router that direct incoming requests to different virtual nodes.

```typescript
const router = mesh.addVirtualRouter('router', {
listener: {
portMapping: {
port: 8081,
protocol: Protocol.HTTP,
}
}
listeners: [ appmesh.VirtualRouterListener.http(8080) ],
});
```

The router can also be created using the constructor and passing in the mesh instead of calling the addVirtualRouter() method for the mesh.
The router can also be created using the constructor and passing in the mesh instead of calling the `addVirtualRouter()` method for the mesh.
The same pattern applies to all constructs within the appmesh library, for any mesh.addXZY method, a new constuctor can also be used.
This is particularly useful for cross stack resources are required.
Where creating the `mesh` as part of an infrastructure stack and creating the `resources` such as `nodes` is more useful to keep in the application stack.

```typescript
const mesh = new Mesh(stack, 'AppMesh', {
Expand All @@ -78,18 +77,15 @@ const mesh = new Mesh(stack, 'AppMesh', {

const router = new VirtualRouter(stack, 'router', {
mesh, // notice that mesh is a required property when creating a router with a new statement
listener: {
portMapping: {
port: 8081,
protocol: Protocol.HTTP,
}
listeners: [ appmesh.VirtualRouterListener.http(8081) ]
}
});
```

The listener protocol can be either `HTTP` or `TCP`.

The same pattern applies to all constructs within the appmesh library, for any mesh.addXZY method, a new constuctor can also be used. This is particularly useful for cross stack resources are required. Where creating the `mesh` as part of an infrastructure stack and creating the `resources` such as `nodes` is more useful to keep in the application stack.
The _VirtualRouterListener_ class provides an easy interface for defining new protocol specific listeners.
The `http()`, `http2()`, `grpc()` and `tcp()` methods are available for use.
They accept a single port parameter, that is used to define what port to match requests on.
The port parameter can be omitted, and it will default to port 8080.

## Adding VirtualService

Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-appmesh/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './route';
export * from './shared-interfaces';
export * from './virtual-node';
export * from './virtual-router';
export * from './virtual-router-listener';
export * from './virtual-service';
export * from './virtual-gateway';
export * from './virtual-gateway-listener';
Expand Down
82 changes: 82 additions & 0 deletions packages/@aws-cdk/aws-appmesh/lib/virtual-router-listener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as cdk from '@aws-cdk/core';
import { CfnVirtualRouter } from './appmesh.generated';
import { Protocol } from './shared-interfaces';

/**
* Properties for a VirtualRouter listener
*/
export interface VirtualRouterListenerConfig {
/**
* Single listener config for a VirtualRouter
*/
readonly listener: CfnVirtualRouter.VirtualRouterListenerProperty;
}

/**
* Represents the properties needed to define listeners for a VirtualRouter
*/
export abstract class VirtualRouterListener {
/**
* Returns an HTTP Listener for a VirtualRouter
*
* @param port the optional port of the listener, 8080 by default
*/
public static http(port?: number): VirtualRouterListener {
return new VirtualRouterListenerImpl(Protocol.HTTP, port);
}

/**
* Returns an HTTP2 Listener for a VirtualRouter
*
* @param port the optional port of the listener, 8080 by default
*/
public static http2(port?: number): VirtualRouterListener {
return new VirtualRouterListenerImpl(Protocol.HTTP2, port);
}

/**
* Returns a GRPC Listener for a VirtualRouter
*
* @param port the optional port of the listener, 8080 by default
*/
public static grpc(port?: number): VirtualRouterListener {
return new VirtualRouterListenerImpl(Protocol.GRPC, port);
}

/**
* Returns a TCP Listener for a VirtualRouter
*
* @param port the optional port of the listener, 8080 by default
*/
public static tcp(port?: number): VirtualRouterListener {
dfezzie marked this conversation as resolved.
Show resolved Hide resolved
return new VirtualRouterListenerImpl(Protocol.TCP, port);
}

/**
* Called when the VirtualRouterListener type is initialized. Can be used to enforce
* mutual exclusivity
*/
public abstract bind(scope: cdk.Construct): VirtualRouterListenerConfig;
}

class VirtualRouterListenerImpl extends VirtualRouterListener {
private readonly protocol: Protocol;
private readonly port: number;

constructor(protocol: Protocol, port?: number) {
super();
this.protocol = protocol;
this.port = port ?? 8080;
}

bind(_scope: cdk.Construct): VirtualRouterListenerConfig {
return {
listener: {
portMapping: {
port: this.port,
protocol: this.protocol,
},
},
};
}
}
27 changes: 9 additions & 18 deletions packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Construct } from 'constructs';
import { CfnVirtualRouter } from './appmesh.generated';
import { IMesh, Mesh } from './mesh';
import { Route, RouteBaseProps } from './route';
import { PortMapping, Protocol } from './shared-interfaces';
import { VirtualRouterListener } from './virtual-router-listener';

/**
* Interface which all VirtualRouter based classes MUST implement
Expand Down Expand Up @@ -43,7 +43,7 @@ export interface VirtualRouterBaseProps {
*
* @default - A listener on HTTP port 8080
*/
readonly listener?: Listener;
readonly listeners?: VirtualRouterListener[];
dfezzie marked this conversation as resolved.
Show resolved Hide resolved

/**
* The name of the VirtualRouter
Expand All @@ -53,16 +53,6 @@ export interface VirtualRouterBaseProps {
readonly virtualRouterName?: string;
}

/**
* A single listener for
*/
export interface Listener {
/**
* Listener port for the VirtualRouter
*/
readonly portMapping: PortMapping;
}

abstract class VirtualRouterBase extends cdk.Resource implements IVirtualRouter {
/**
* The name of the VirtualRouter
Expand Down Expand Up @@ -155,8 +145,11 @@ export class VirtualRouter extends VirtualRouterBase {
});

this.mesh = props.mesh;

this.addListener(props.listener || { portMapping: { port: 8080, protocol: Protocol.HTTP } });
if (props.listeners && props.listeners.length) {
props.listeners.forEach(listener => this.addListener(listener));
} else {
this.addListener(VirtualRouterListener.http());
}

const router = new CfnVirtualRouter(this, 'Resource', {
virtualRouterName: this.physicalName,
Expand All @@ -177,10 +170,8 @@ export class VirtualRouter extends VirtualRouterBase {
/**
* Add port mappings to the router
*/
private addListener(listener: Listener) {
this.listeners.push({
portMapping: listener.portMapping,
});
private addListener(listener: VirtualRouterListener) {
this.listeners.push(listener.bind(this).listener);
}
}

Expand Down
9 changes: 3 additions & 6 deletions packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ const namespace = new cloudmap.PrivateDnsNamespace(stack, 'test-namespace', {

const mesh = new appmesh.Mesh(stack, 'mesh');
const router = mesh.addVirtualRouter('router', {
listener: {
portMapping: {
port: 8080,
protocol: appmesh.Protocol.HTTP,
},
},
listeners: [
appmesh.VirtualRouterListener.http(),
],
});

const virtualService = mesh.addVirtualService('service', {
Expand Down
27 changes: 7 additions & 20 deletions packages/@aws-cdk/aws-appmesh/test/test.mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,7 @@ export = {
meshName: 'test-mesh',
});

mesh.addVirtualRouter('router', {
listener: {
portMapping: {
port: 8080,
protocol: appmesh.Protocol.HTTP,
},
},
});
mesh.addVirtualRouter('router');

// THEN
expect(stack).to(
Expand Down Expand Up @@ -147,12 +140,9 @@ export = {
});

const testRouter = mesh.addVirtualRouter('router', {
listener: {
portMapping: {
port: 8080,
protocol: appmesh.Protocol.HTTP,
},
},
listeners: [
appmesh.VirtualRouterListener.http(),
],
});

// THEN
Expand All @@ -178,12 +168,9 @@ export = {
});

const testRouter = mesh.addVirtualRouter('test-router', {
listener: {
portMapping: {
port: 8080,
protocol: appmesh.Protocol.HTTP,
},
},
listeners: [
appmesh.VirtualRouterListener.http(),
],
dfezzie marked this conversation as resolved.
Show resolved Hide resolved
});

mesh.addVirtualService('service', {
Expand Down
82 changes: 82 additions & 0 deletions packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,88 @@ import { Test } from 'nodeunit';
import * as appmesh from '../lib';

export = {
'When creating a VirtualRouter': {
'should have appropriate defaults'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const mesh = new appmesh.Mesh(stack, 'mesh', {
meshName: 'test-mesh',
});
// WHEN
mesh.addVirtualRouter('http-router-listener');

expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualRouter', {
VirtualRouterName: 'meshhttprouterlistenerF57BCB2F',
Spec: {
Listeners: [
{
PortMapping: {
Port: 8080,
Protocol: appmesh.Protocol.HTTP,
},
},
],
},
}));
test.done();
},
'should have protocol variant listeners'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const mesh = new appmesh.Mesh(stack, 'mesh', {
meshName: 'test-mesh',
});
// WHEN
mesh.addVirtualRouter('http-router-listener', {
listeners: [
appmesh.VirtualRouterListener.http(),
],
virtualRouterName: 'http-router-listener',
});

mesh.addVirtualRouter('http2-router-listener', {
listeners: [
appmesh.VirtualRouterListener.http2(),
],
virtualRouterName: 'http2-router-listener',
});

mesh.addVirtualRouter('grpc-router-listener', {
listeners: [
appmesh.VirtualRouterListener.grpc(),
],
virtualRouterName: 'grpc-router-listener',
});

mesh.addVirtualRouter('tcp-router-listener', {
listeners: [
appmesh.VirtualRouterListener.tcp(),
],
virtualRouterName: 'tcp-router-listener',
});

// THEN
const expectedPorts = [appmesh.Protocol.HTTP, appmesh.Protocol.HTTP2, appmesh.Protocol.GRPC, appmesh.Protocol.TCP];
expectedPorts.forEach(protocol => {
expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualRouter', {
VirtualRouterName: `${protocol}-router-listener`,
Spec: {
Listeners: [
{
PortMapping: {
Port: 8080,
Protocol: protocol,
},
},
],
},
}));
});

test.done();
},
},
dfezzie marked this conversation as resolved.
Show resolved Hide resolved

'When adding route to existing VirtualRouter': {
'should create route resource'(test: Test) {
// GIVEN
Expand Down