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 VirtualService provider to a union-like class #11978

Merged
merged 20 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from 19 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 @@ -316,8 +316,7 @@ export class AppMeshExtension extends ServiceExtension {
// Now create a virtual service. Relationship goes like this:
// virtual service -> virtual router -> virtual node
this.virtualService = new appmesh.VirtualService(this.scope, `${this.parentService.id}-virtual-service`, {
mesh: this.mesh,
virtualRouter: this.virtualRouter,
virtualServiceProvider: appmesh.VirtualServiceProvider.virtualRouter(this.virtualRouter),
virtualServiceName: serviceName,
});
}
Expand Down
14 changes: 6 additions & 8 deletions packages/@aws-cdk/aws-appmesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,23 +109,21 @@ When creating a virtual service:
Adding a virtual router as the provider:

```ts
mesh.addVirtualService('virtual-service', {
virtualRouter: router,
virtualServiceName: 'my-service.default.svc.cluster.local',
new appmesh.VirtualService('virtual-service', {
virtualServiceName: 'my-service.default.svc.cluster.local', // optional
virtualServiceProvider: appmesh.VirtualServiceProvider.virtualRouter(router),
});
```

Adding a virtual node as the provider:

```ts
mesh.addVirtualService('virtual-service', {
virtualNode: node,
virtualServiceName: `my-service.default.svc.cluster.local`,
new appmesh.VirtualService('virtual-service', {
virtualServiceName: `my-service.default.svc.cluster.local`, // optional
virtualServiceProvider: appmesh.VirtualServiceProvider.virtualNode(node),
});
```

**Note** that only one must of `virtualNode` or `virtualRouter` must be chosen.

## Adding a VirtualNode

A `virtual node` acts as a logical pointer to a particular task group, such as an Amazon ECS service or a Kubernetes deployment.
Expand Down
16 changes: 0 additions & 16 deletions packages/@aws-cdk/aws-appmesh/lib/mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { CfnMesh } from './appmesh.generated';
import { VirtualGateway, VirtualGatewayBaseProps } from './virtual-gateway';
import { VirtualNode, VirtualNodeBaseProps } from './virtual-node';
import { VirtualRouter, VirtualRouterBaseProps } from './virtual-router';
import { VirtualService, VirtualServiceBaseProps } from './virtual-service';

/**
* A utility enum defined for the egressFilter type property, the default of DROP_ALL,
Expand Down Expand Up @@ -46,11 +45,6 @@ export interface IMesh extends cdk.IResource {
*/
addVirtualRouter(id: string, props?: VirtualRouterBaseProps): VirtualRouter;

/**
* Adds a VirtualService with the given id
*/
addVirtualService(id: string, props?: VirtualServiceBaseProps): VirtualService;

/**
* Adds a VirtualNode to the Mesh
*/
Expand Down Expand Up @@ -86,16 +80,6 @@ abstract class MeshBase extends cdk.Resource implements IMesh {
});
}

/**
* Adds a VirtualService with the given id
*/
public addVirtualService(id: string, props: VirtualServiceBaseProps = {}): VirtualService {
return new VirtualService(this, id, {
...props,
mesh: this,
});
}

/**
* Adds a VirtualNode to the Mesh
*/
Expand Down
157 changes: 101 additions & 56 deletions packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export interface IVirtualService extends cdk.IResource {
}

/**
* The base properties which all classes in VirtualService will inherit from
* The properties applied to the VirtualService being defined
*/
export interface VirtualServiceBaseProps {
export interface VirtualServiceProps {
/**
* The name of the VirtualService.
*
Expand All @@ -50,36 +50,17 @@ export interface VirtualServiceBaseProps {
*/
readonly virtualServiceName?: string;

/**
* The VirtualRouter which the VirtualService uses as provider
*
* @default - At most one of virtualRouter and virtualNode is allowed.
*/
readonly virtualRouter?: IVirtualRouter;

/**
* The VirtualNode attached to the virtual service
*
* @default - At most one of virtualRouter and virtualNode is allowed.
*/
readonly virtualNode?: IVirtualNode;

/**
* Client policy for this Virtual Service
*
* @default - none
*/
readonly clientPolicy?: ClientPolicy;
}

/**
* The properties applied to the VirtualService being define
*/
export interface VirtualServiceProps extends VirtualServiceBaseProps {
/**
* The Mesh which the VirtualService belongs to
* The VirtualNode or VirtualRouter which the VirtualService uses as its provider
*/
readonly mesh: IMesh;
readonly virtualServiceProvider: VirtualServiceProvider;
dfezzie marked this conversation as resolved.
Show resolved Hide resolved
}

dfezzie marked this conversation as resolved.
Show resolved Hide resolved
/**
Expand Down Expand Up @@ -135,59 +116,35 @@ export class VirtualService extends cdk.Resource implements IVirtualService {

public readonly clientPolicy?: ClientPolicy;

private readonly virtualServiceProvider?: CfnVirtualService.VirtualServiceProviderProperty;

constructor(scope: Construct, id: string, props: VirtualServiceProps) {
super(scope, id, {
physicalName: props.virtualServiceName || cdk.Lazy.string({ produce: () => cdk.Names.uniqueId(this) }),
});

if (props.virtualNode && props.virtualRouter) {
throw new Error('Must provide only one of virtualNode or virtualRouter for the provider');
}

this.mesh = props.mesh;
this.clientPolicy = props.clientPolicy;

// Check which provider to use node or router (or neither)
if (props.virtualRouter) {
this.virtualServiceProvider = this.addVirtualRouter(props.virtualRouter.virtualRouterName);
}
if (props.virtualNode) {
this.virtualServiceProvider = this.addVirtualNode(props.virtualNode.virtualNodeName);
}
const providerConfig = props.virtualServiceProvider.bind(this);
this.mesh = providerConfig.mesh;

const svc = new CfnVirtualService(this, 'Resource', {
meshName: this.mesh.meshName,
virtualServiceName: this.physicalName,
spec: {
provider: this.virtualServiceProvider,
provider: providerConfig.virtualNodeProvider || providerConfig.virtualRouterProvider
? {
virtualNode: providerConfig.virtualNodeProvider,
virtualRouter: providerConfig.virtualRouterProvider,
}
: undefined,
},
});

this.virtualServiceName = this.getResourceNameAttribute(svc.attrVirtualServiceName);
this.virtualServiceArn = this.getResourceArnAttribute(svc.ref, {
service: 'appmesh',
resource: `mesh/${props.mesh.meshName}/virtualService`,
resource: `mesh/${this.mesh.meshName}/virtualService`,
resourceName: this.physicalName,
});
}

private addVirtualRouter(name: string): CfnVirtualService.VirtualServiceProviderProperty {
return {
virtualRouter: {
virtualRouterName: name,
},
};
}

private addVirtualNode(name: string): CfnVirtualService.VirtualServiceProviderProperty {
return {
virtualNode: {
virtualNodeName: name,
},
};
}
}

/**
Expand All @@ -211,3 +168,91 @@ export interface VirtualServiceAttributes {
*/
readonly clientPolicy?: ClientPolicy;
}

/**
* Properties for a VirtualService provider
*/
export interface VirtualServiceProviderConfig {
/**
* Virtual Node based provider
*
* @default - none
*/
readonly virtualNodeProvider?: CfnVirtualService.VirtualNodeServiceProviderProperty;

/**
* Virtual Router based provider
*
* @default - none
*/
readonly virtualRouterProvider?: CfnVirtualService.VirtualRouterServiceProviderProperty;
skinny85 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Mesh the Provider is using
*
* @default - none
*/
readonly mesh: IMesh;
}

/**
* Represents the properties needed to define the provider for a VirtualService
*/
export abstract class VirtualServiceProvider {
/**
* Returns a VirtualNode based Provider for a VirtualService
*/
public static virtualNode(virtualNode: IVirtualNode): VirtualServiceProvider {
return new VirtualServiceProviderImpl(virtualNode, undefined);
}

/**
* Returns a VirtualRouter based Provider for a VirtualService
*/
public static virtualRouter(virtualRouter: IVirtualRouter): VirtualServiceProvider {
return new VirtualServiceProviderImpl(undefined, virtualRouter);
}

skinny85 marked this conversation as resolved.
Show resolved Hide resolved
/**
* Returns an Empty Provider for a VirtualService. This provides no routing capabilities
* and should only be used as a placeholder
*/
public static none(mesh: IMesh): VirtualServiceProvider {
return new VirtualServiceProviderImpl(undefined, undefined, mesh);
}

/**
* Enforces mutual exclusivity for VirtualService provider types.
*/
public abstract bind(_construct: Construct): VirtualServiceProviderConfig;
}

class VirtualServiceProviderImpl extends VirtualServiceProvider {
private readonly virtualNode?: IVirtualNode;
private readonly virtualRouter?: IVirtualRouter;
private readonly mesh: IMesh;

constructor(virtualNode?: IVirtualNode, virtualRouter?: IVirtualRouter, mesh?: IMesh) {
super();
this.virtualNode = virtualNode;
this.virtualRouter = virtualRouter;
const providedMesh = this.virtualNode?.mesh ?? this.virtualRouter?.mesh ?? mesh!;
this.mesh = providedMesh;
}

public bind(_construct: Construct): VirtualServiceProviderConfig {
return {
mesh: this.mesh,
virtualNodeProvider: this.virtualNode
? {
virtualNodeName: this.virtualNode.virtualNodeName,
}
: undefined,
virtualRouterProvider: this.virtualRouter
? {
virtualRouterName: this.virtualRouter.virtualRouterName,
}
: undefined,
};
}
}
Loading