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): add Virtual Gateways and Gateway Routes #10879

Merged
merged 42 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5cab38c
Initial VGW commit
Sep 29, 2020
71ac7dd
Update with upstream changes
Oct 1, 2020
0cf538a
Add initial round of tests
Oct 2, 2020
1849af9
Fixes a bug with default paths on health checks
Oct 2, 2020
4e26790
Implements Gateway Routes
Oct 14, 2020
9c7dc48
Adds routeType to GatewayRouteBaseProps
Oct 14, 2020
0d47976
Update packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts
dfezzie Oct 15, 2020
463f507
Reworks Gateway Routes to use bind classes for protocol spec variants
Oct 16, 2020
860a40a
Merge branch 'master' into gateway
Oct 16, 2020
d2c59bb
Adds addListener to VGW
Oct 16, 2020
4976d8f
Adds gateway listener protocol variant classes
Oct 16, 2020
ce2f325
Adds addListener method to IVirtualGateway
Oct 16, 2020
45690a9
Merge branch 'master' into gateway
Oct 21, 2020
2939e5c
Fixes some build issues
Oct 21, 2020
a242bfd
adds utility method to add multiple gateway routes to a VirtualGateway
Oct 21, 2020
a97a5c5
adds more tests to gateway routes
Oct 21, 2020
0016549
adds integ tests for gateway routes
Oct 21, 2020
5a54ab5
Updates README and adds tests for adding multiple gateway routes
Oct 21, 2020
2b36223
Merge branch 'master' into gateway
Oct 21, 2020
ca1d0b3
Apply suggestions from code review
dfezzie Oct 21, 2020
92dd147
refactor gateway route spec related code into a separate file
Oct 21, 2020
4c9a69c
add a newline between properties
Oct 21, 2020
214177c
do not export gateway listeners
Oct 21, 2020
93ded0e
removes fromResourceName methods and replaces it with fromResourceAtt…
Oct 22, 2020
b737de6
makes error message more specific for prefixPath
Oct 22, 2020
2689cc0
Merge branch 'master' into gateway
Oct 22, 2020
48900ef
Apply suggestions from code review
dfezzie Oct 26, 2020
1df5158
Merge branch 'master' into gateway
dfezzie Oct 26, 2020
bcd5425
Revert "removes fromResourceName methods and replaces it with fromRes…
Oct 26, 2020
94e79a8
Update README with requested changes
Oct 26, 2020
9cd6eb6
Addresses PR comments
Oct 26, 2020
14df61e
bind method for gateway listeners no longer returns raw cfn spec
Oct 26, 2020
b30faaf
uses inheritance for http2 gateway listener and removes fromName() me…
Oct 26, 2020
a86c57b
add protocol variant tests for gateway routes
Oct 26, 2020
4e432c2
addresses smaller changes from review
Oct 28, 2020
e550d53
moves gateway listener classes to separate file and adds health check…
Oct 28, 2020
7813bbc
removes addListener() methods from virtual gateways
Oct 28, 2020
8670dbd
removes the ListenerBase interface
Oct 28, 2020
c01eb4c
Merge branch 'master' into gateway
Oct 28, 2020
5efc195
remove validation for only having 1 listener on virtual gateways
Oct 29, 2020
1eda686
Merge branch 'master' into gateway
Oct 29, 2020
519fc23
Merge branch 'master' into gateway
skinny85 Oct 29, 2020
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
364 changes: 364 additions & 0 deletions packages/@aws-cdk/aws-appmesh/lib/gateway-route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,364 @@
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnGatewayRoute } from './appmesh.generated';
import { Protocol } from './shared-interfaces';
import { IVirtualGateway } from './virtual-gateway';
import { IVirtualService } from './virtual-service';

/**
* Interface for which all Gateway Route based classes MUST implement
*/
export interface IGatewayRoute extends cdk.IResource {
/**
* The name of the Gateway Route
*
* @attribute
*/
readonly gatewayRouteName: string,

/**
* The Amazon Resource Name (ARN) for the Gateway Route
*
* @attribute
*/
readonly gatewayRouteArn: string;
}

interface GatewayRouteBaseProps {
/**
* The name of the Gateway Route
*
* @default - an automatically generated name
*/
readonly gatewayRouteName?: string;

/**
* The VirtualService this Gateway Route directs traffic to
*/
readonly routeTarget: IVirtualService;

/**
* What protocol the route uses
*/
readonly routeType: Protocol.GRPC | Protocol.HTTP | Protocol.HTTP2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder - is the reason the type is not simply Protocol because there's no TCP Gateway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wanted to reuse Protocol for this, but scope it down to not include TCP. Would you suggest creating a separate enum?

}

/**
* Base interface for HTTP Based Gateway Routes
*/
export interface GatewayHttpRouteBaseProps extends GatewayRouteBaseProps {
/**
* The criterion for determining a request match for this Gateway Route.
*
* @default - prefix match on "/"
*/
readonly match?: GatewayHttpRouteMatch;
/**
* HTTP Procol
*/
readonly routeType: Protocol.HTTP;
}

/**
* Interface for HTTP Based Gateway Routes
*/
export interface GatewayHttpRouteProps extends GatewayHttpRouteBaseProps {
/**
* The Virtual Gateway this Gateway Route is associated with
*/
readonly virtualGateway: IVirtualGateway;
}

/**
* Base interface for HTTP2 Based Gateway Routes
*/
export interface GatewayHttp2RouteBaseProps extends GatewayRouteBaseProps {
/**
* The criterion for determining a request match for this Gateway Route.
*
* @default - prefix match on "/"
*/
readonly match?: GatewayHttp2RouteMatch;
dfezzie marked this conversation as resolved.
Show resolved Hide resolved
/**
* HTTP2 Procol
*/
readonly routeType: Protocol.HTTP2;
}

/**
* Interface for HTTP2 Based Gateway Routes
*/
export interface GatewayHttp2RouteProps extends GatewayHttp2RouteBaseProps {
/**
* The Virtual Gateway this Gateway Route is associated with
*/
readonly virtualGateway: IVirtualGateway;
}

/**
* Base interface for GRPC Based Gateway Routes
*/
export interface GatewayGrpcRouteBaseProps extends GatewayRouteBaseProps {
/**
* The criterion for determining a request match for this Gateway Route.
*
* @default - no default
*/
readonly match: GatewayGrpcRouteMatch;
/**
* GRPC Protocol
*/
readonly routeType: Protocol.GRPC;
}

/**
* Interface for GRPC Based Gateway Routes
*/
export interface GatewayGrpcRouteProps extends GatewayGrpcRouteBaseProps {
/**
* The Virtual Gateway this Gateway Route is associated with
*/
readonly virtualGateway: IVirtualGateway;
}

interface GatewayHttpSharedRouteMatch {
/**
* Specifies the path to match requests with.
* This parameter must always start with /, which by itself matches all requests to the virtual service name.
* You can also match for path-based routing of requests. For example, if your virtual service name is my-service.local
* and you want the route to match requests to my-service.local/metrics, your prefix should be /metrics.
*
*/
readonly prefixPath: string;
}

/**
* The criterion for determining a request match for this Gateway Route
*/
export interface GatewayHttpRouteMatch extends GatewayHttpSharedRouteMatch {}

/**
* The criterion for determining a request match for this Gateway Route
*/
export interface GatewayHttp2RouteMatch extends GatewayHttpSharedRouteMatch {}

/**
* The criterion for determining a request match for this Gateway Route
*/
export interface GatewayGrpcRouteMatch {
/**
* The fully qualified domain name for the service to match from the request
*/
readonly serviceName: string;
}

/**
* Properties to define new Gateway Routes
*/
export interface GatewayRouteProps extends GatewayRouteBaseProps {
/**
* The Virtual Gateway this Gateway Route is associated with
*/
readonly virtualGateway: IVirtualGateway;
}

/**
* Gateway Route represents a new or existing gateway route attached to a VirtualGateway and Mesh
*
* @see https://docs.aws.amazon.com/app-mesh/latest/userguide/gateway-routes.html
*/
export class GatewayRoute extends cdk.Resource implements IGatewayRoute {
skinny85 marked this conversation as resolved.
Show resolved Hide resolved
/**
* Import an existing Gateway Route given an ARN
*/
public static fromGatewayRouteArn(scope: Construct, id: string, gatewayRouteArn: string): IGatewayRoute {
return new ImportedGatewayRoute(scope, id, { gatewayRouteArn });
}

/**
* Import an existing Gateway Route given its name
*/
public static fromGatewayRouteName(
dfezzie marked this conversation as resolved.
Show resolved Hide resolved
scope: Construct, id: string, meshName: string, virtualGatewayName: string, gatewayRouteName: string): IGatewayRoute {
return new ImportedGatewayRoute(scope, id, { meshName, virtualGatewayName, gatewayRouteName });
}

/**
* The name of the Gateway Route
*/
public readonly gatewayRouteName: string;

/**
* The Amazon Resource Name (ARN) for the Gateway Route
*/
public readonly gatewayRouteArn: string;

/**
* The VirtualGateway this GatewayRoute is a part of
*/
public readonly virtualGateway: IVirtualGateway;

private readonly httpRoute?: CfnGatewayRoute.HttpGatewayRouteProperty;
private readonly http2Route?: CfnGatewayRoute.HttpGatewayRouteProperty;
private readonly grpcRoute?: CfnGatewayRoute.GrpcGatewayRouteProperty;

constructor(scope: Construct, id: string, props: GatewayHttpRouteProps | GatewayHttp2RouteProps | GatewayGrpcRouteProps) {
super(scope, id, {
physicalName: props.gatewayRouteName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }),
});

this.virtualGateway = props.virtualGateway;

if (props.routeType === Protocol.HTTP) {
this.httpRoute = this.renderHttpRoute(props);
}
if (props.routeType === Protocol.HTTP2) {
this.http2Route = this.renderHttpRoute(props);
}
if (props.routeType === Protocol.GRPC) {
this.grpcRoute = this.renderGrpcRoute(props);
}

const gatewayRoute = new CfnGatewayRoute(this, 'Resource', {
gatewayRouteName: this.physicalName,
meshName: props.virtualGateway.mesh.meshName,
spec: {
httpRoute: this.httpRoute,
http2Route: this.http2Route,
grpcRoute: this.grpcRoute,
},
virtualGatewayName: this.virtualGateway.virtualGatewayName,
});

this.gatewayRouteName = this.getResourceNameAttribute(gatewayRoute.attrGatewayRouteName);
this.gatewayRouteArn = this.getResourceArnAttribute(gatewayRoute.ref, {
service: 'appmesh',
resource: `mesh/${props.virtualGateway.mesh.meshName}/virtualRouter/${this.virtualGateway.virtualGatewayName}/gatewayRoute`,
resourceName: this.physicalName,
});
}

private renderHttpRoute(props: GatewayHttpRouteProps | GatewayHttp2RouteProps): CfnGatewayRoute.HttpGatewayRouteProperty {
const prefixPath = props.match ? props.match.prefixPath : '/';
if (prefixPath[0] != '/') {
throw new Error('Prefix Path must start with \'/\'');
}
return {
action: {
target: {
virtualService: {
virtualServiceName: props.routeTarget.virtualServiceName,
},
},
},
match: {
prefix: prefixPath,
},
};
}

private renderGrpcRoute(props: GatewayGrpcRouteProps): CfnGatewayRoute.GrpcGatewayRouteProperty {
return {
action: {
target: {
virtualService: {
virtualServiceName: props.routeTarget.virtualServiceName,
},
},
},
match: {
serviceName: props.match.serviceName,
},
};
}
}

/**
* HTTP Gateway Route attached to a VirtualGateway and Mesh
*
* @see https://docs.aws.amazon.com/app-mesh/latest/userguide/gateway-routes.html
*/
export class GatewayHttpRoute extends GatewayRoute {
constructor(scope: Construct, id: string, props: GatewayHttpRouteProps) {
super(scope, id, props);
}
}

/**
* HTTP2 Gateway Route attached to a VirtualGateway and Mesh
*
* @see https://docs.aws.amazon.com/app-mesh/latest/userguide/gateway-routes.html
*/
export class GatewayHttp2Route extends GatewayRoute {
constructor(scope: Construct, id: string, props: GatewayHttp2RouteProps) {
super(scope, id, props);
}
}

/**
* GRPC Gateway Route attached to a VirtualGateway and Mesh
*
* @see https://docs.aws.amazon.com/app-mesh/latest/userguide/gateway-routes.html
*/
export class GatewayGrpcRoute extends GatewayRoute {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that these are empty suggests to me the modeling is not quite right here 🙂

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

/**
* Interface with properties necessary to import a reusable Gateway Route
*/
interface GatewayRouteAttributes {
/**
* The name of the Gateway Route
*/
readonly gatewayRouteName?: string;

/**
* The Amazon Resource Name (ARN) for the Gateway Route
*/
readonly gatewayRouteArn?: string;
skinny85 marked this conversation as resolved.
Show resolved Hide resolved

/**
* The name of the mesh this Gateway Route is associated with
*/
readonly meshName?: string;
dfezzie marked this conversation as resolved.
Show resolved Hide resolved

/**
* The name of the Virtual Gateway this Gateway Route is associated with
*/
readonly virtualGatewayName?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be IVirtualGateway, not just the name.

}

/**
* Represents an imported IGatewayRoute
*/
class ImportedGatewayRoute extends cdk.Resource implements IGatewayRoute {
/**
* The name of the Gateway Route
*/
public gatewayRouteName: string;

/**
* The Amazon Resource Name (ARN) for the Gateway Route
*/
public gatewayRouteArn: string;

constructor(scope: Construct, id: string, props: GatewayRouteAttributes) {
super(scope, id);
if (props.gatewayRouteArn) {
dfezzie marked this conversation as resolved.
Show resolved Hide resolved
this.gatewayRouteArn = props.gatewayRouteArn;
this.gatewayRouteName = cdk.Fn.select(4, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.gatewayRouteArn).resourceName!));
} else if (props.gatewayRouteName && props.meshName && props.virtualGatewayName) {
this.gatewayRouteName = props.gatewayRouteName;
this.gatewayRouteArn = cdk.Stack.of(this).formatArn({
service: 'appmesh',
resource: `mesh/${props.meshName}/virtualGateway/${props.virtualGatewayName}/gatewayRoute`,
resourceName: this.gatewayRouteName,
});
} else {
throw new Error('Need either arn or three names');
}
}
}
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-appmesh/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export * from './shared-interfaces';
export * from './virtual-node';
export * from './virtual-router';
export * from './virtual-service';
export * from './virtual-gateway';
export * from './gateway-route';
Loading