From 13d713e6358b29e55a626c44c7b2f0dcd946fddc Mon Sep 17 00:00:00 2001 From: Dominic Fezzie Date: Fri, 6 Nov 2020 12:40:48 -0800 Subject: [PATCH] feat(appmesh): remove from*Name() methods and replace with from*Attributes() (#11266) Follow Up from https://github.com/aws/aws-cdk/pull/10879 BREAKING CHANGE: all `fromResourceName()` methods in the AppMesh module have been replaced with `fromResourceAttributes()` ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-appmesh/README.md | 29 +++++ .../@aws-cdk/aws-appmesh/lib/gateway-route.ts | 70 ++++------- packages/@aws-cdk/aws-appmesh/lib/route.ts | 88 +++++--------- .../aws-appmesh/lib/virtual-gateway.ts | 76 +++++------- .../@aws-cdk/aws-appmesh/lib/virtual-node.ts | 92 ++++++--------- .../aws-appmesh/lib/virtual-router.ts | 111 ++++-------------- .../aws-appmesh/lib/virtual-service.ts | 95 ++++++--------- .../aws-appmesh/test/test.gateway-route.ts | 39 +++++- .../@aws-cdk/aws-appmesh/test/test.route.ts | 74 +++++------- .../aws-appmesh/test/test.virtual-gateway.ts | 33 +++++- .../aws-appmesh/test/test.virtual-node.ts | 65 ++++------ .../aws-appmesh/test/test.virtual-router.ts | 29 ++++- .../aws-appmesh/test/test.virtual-service.ts | 44 +++---- 13 files changed, 370 insertions(+), 475 deletions(-) diff --git a/packages/@aws-cdk/aws-appmesh/README.md b/packages/@aws-cdk/aws-appmesh/README.md index e38a8ea49a9e9..00d70bd8b0888 100644 --- a/packages/@aws-cdk/aws-appmesh/README.md +++ b/packages/@aws-cdk/aws-appmesh/README.md @@ -307,3 +307,32 @@ gateway.addGatewayRoute('gateway-route-grpc', { }), }); ``` + +## Importing Resources + +Each mesh resource comes with two static methods for importing a reference to an existing App Mesh resource. +These imported resources can be used as references for other resources in your mesh. +There are two static methods, `fromArn` and `fromAttributes` where the `` is replaced with the resource name. + +```typescript +const arn = "arn:aws:appmesh:us-east-1:123456789012:mesh/testMesh/virtualNode/testNode"; +appmesh.VirtualNode.fromVirtualNodeArn(stack, 'importedVirtualNode', arn); +``` + +```typescript +appmesh.VirtualNode.fromVirtualNodeAttributes(stack, 'imported-virtual-node', { + mesh: appmesh.Mesh.fromMeshName(stack, 'Mesh', 'testMesh'), + virtualNodeName: virtualNodeName, +}); +``` + +To import a mesh, there are two static methods, `fromMeshArn` and `fromMeshName`. + +```typescript +const arn = 'arn:aws:appmesh:us-east-1:123456789012:mesh/testMesh'; +appmesh.Mesh.fromMeshArn(stack, 'imported-mesh', arn); +``` + +```typescript +appmesh.Mesh.fromMeshName(stack, 'imported-mesh', 'abc'); +``` diff --git a/packages/@aws-cdk/aws-appmesh/lib/gateway-route.ts b/packages/@aws-cdk/aws-appmesh/lib/gateway-route.ts index cc00c0f632ac3..5bfb3b0ca21cd 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/gateway-route.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/gateway-route.ts @@ -65,7 +65,26 @@ export class GatewayRoute extends cdk.Resource implements IGatewayRoute { * Import an existing GatewayRoute given an ARN */ public static fromGatewayRouteArn(scope: Construct, id: string, gatewayRouteArn: string): IGatewayRoute { - return new ImportedGatewayRoute(scope, id, { gatewayRouteArn }); + return new class extends cdk.Resource implements IGatewayRoute { + readonly gatewayRouteArn = gatewayRouteArn; + readonly gatewayRouteName = cdk.Fn.select(4, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(gatewayRouteArn).resourceName!)); + readonly virtualGateway = VirtualGateway.fromVirtualGatewayArn(this, 'virtualGateway', gatewayRouteArn); + }(scope, id); + } + + /** + * Import an existing GatewayRoute given attributes + */ + public static fromGatewayRouteAttributes(scope: Construct, id: string, attrs: GatewayRouteAttributes): IGatewayRoute { + return new class extends cdk.Resource implements IGatewayRoute { + readonly gatewayRouteName = attrs.gatewayRouteName; + readonly gatewayRouteArn = cdk.Stack.of(scope).formatArn({ + service: 'appmesh', + resource: `mesh/${attrs.virtualGateway.mesh.meshName}/virtualGateway/${attrs.virtualGateway.virtualGatewayName}/gatewayRoute`, + resourceName: this.gatewayRouteName, + }); + readonly virtualGateway = attrs.virtualGateway; + }(scope, id); } /** @@ -114,55 +133,14 @@ export class GatewayRoute extends cdk.Resource implements IGatewayRoute { /** * Interface with properties necessary to import a reusable GatewayRoute */ -interface GatewayRouteAttributes { +export interface GatewayRouteAttributes { /** * The name of the GatewayRoute */ - readonly gatewayRouteName?: string; + readonly gatewayRouteName: string; /** - * The Amazon Resource Name (ARN) for the GatewayRoute + * The VirtualGateway this GatewayRoute is associated with. */ - readonly gatewayRouteArn?: string; - - /** - * The name of the mesh this GatewayRoute is associated with - */ - readonly meshName?: string; - - /** - * The name of the Virtual Gateway this GatewayRoute is associated with - */ - readonly virtualGateway?: IVirtualGateway; -} - -/** - * Represents an imported IGatewayRoute - */ -class ImportedGatewayRoute extends cdk.Resource implements IGatewayRoute { - /** - * The name of the GatewayRoute - */ - public gatewayRouteName: string; - - /** - * The Amazon Resource Name (ARN) for the GatewayRoute - */ - public gatewayRouteArn: string; - - /** - * The VirtualGateway the GatewayRoute belongs to - */ - public virtualGateway: IVirtualGateway; - - constructor(scope: Construct, id: string, props: GatewayRouteAttributes) { - super(scope, id); - if (props.gatewayRouteArn) { - this.gatewayRouteArn = props.gatewayRouteArn; - this.gatewayRouteName = cdk.Fn.select(4, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.gatewayRouteArn).resourceName!)); - this.virtualGateway = VirtualGateway.fromVirtualGatewayArn(this, 'virtualGateway', props.gatewayRouteArn); - } else { - throw new Error('Need gatewayRouteArn'); - } - } + readonly virtualGateway: IVirtualGateway; } diff --git a/packages/@aws-cdk/aws-appmesh/lib/route.ts b/packages/@aws-cdk/aws-appmesh/lib/route.ts index 696908abc40a6..cfa0e8e6d54c1 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/route.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/route.ts @@ -3,7 +3,7 @@ import { Construct } from 'constructs'; import { CfnRoute } from './appmesh.generated'; import { IMesh } from './mesh'; import { IVirtualNode } from './virtual-node'; -import { IVirtualRouter } from './virtual-router'; +import { IVirtualRouter, VirtualRouter } from './virtual-router'; /** * Interface for which all Route based classes MUST implement @@ -22,6 +22,11 @@ export interface IRoute extends cdk.IResource { * @attribute */ readonly routeArn: string; + + /** + * The VirtualRouter the Route belongs to + */ + readonly virtualRouter: IVirtualRouter; } /** @@ -99,7 +104,7 @@ export interface RouteProps extends RouteBaseProps { readonly mesh: IMesh; /** - * The virtual router in which to define the route + * The VirtualRouter the Route belongs to */ readonly virtualRouter: IVirtualRouter; } @@ -111,21 +116,33 @@ export interface RouteProps extends RouteBaseProps { */ export class Route extends cdk.Resource implements IRoute { /** - * Import an existing route given an ARN + * Import an existing Route given an ARN */ public static fromRouteArn(scope: Construct, id: string, routeArn: string): IRoute { - return new ImportedRoute(scope, id, { routeArn }); + return new class extends cdk.Resource implements IRoute { + readonly routeArn = routeArn; + readonly virtualRouter = VirtualRouter.fromVirtualRouterArn(this, 'VirtualRouter', routeArn); + readonly routeName = cdk.Fn.select(4, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(routeArn).resourceName!)); + }(scope, id); } /** - * Import an existing route given its name + * Import an existing Route given attributes */ - public static fromRouteName(scope: Construct, id: string, meshName: string, virtualRouterName: string, routeName: string): IRoute { - return new ImportedRoute(scope, id, { meshName, virtualRouterName, routeName }); + public static fromRouteAttributes(scope: Construct, id: string, attrs: RouteAttributes): IRoute { + return new class extends cdk.Resource implements IRoute { + readonly routeName = attrs.routeName; + readonly virtualRouter = attrs.virtualRouter; + readonly routeArn = cdk.Stack.of(this).formatArn({ + service: 'appmesh', + resource: `mesh/${attrs.virtualRouter.mesh.meshName}/virtualRouter/${attrs.virtualRouter.virtualRouterName}/route`, + resourceName: this.routeName, + }); + }(scope, id); } /** - * The name of the route + * The name of the Route */ public readonly routeName: string; @@ -135,7 +152,7 @@ export class Route extends cdk.Resource implements IRoute { public readonly routeArn: string; /** - * The virtual router this route is a part of + * The VirtualRouter the Route belongs to */ public readonly virtualRouter: IVirtualRouter; @@ -215,57 +232,14 @@ export class Route extends cdk.Resource implements IRoute { /** * Interface with properties ncecessary to import a reusable Route */ -interface RouteAttributes { - /** - * The name of the route - */ - readonly routeName?: string; - - /** - * The Amazon Resource Name (ARN) for the route - */ - readonly routeArn?: string; - - /** - * The name of the mesh this route is associated with - */ - readonly meshName?: string; - - /** - * The name of the virtual router this route is associated with - */ - readonly virtualRouterName?: string; -} - -/** - * Represents and imported IRoute - */ -class ImportedRoute extends cdk.Resource implements IRoute { +export interface RouteAttributes { /** - * The name of the route + * The name of the Route */ - public readonly routeName: string; + readonly routeName: string; /** - * The Amazon Resource Name (ARN) for the route + * The VirtualRouter the Route belongs to */ - public readonly routeArn: string; - - constructor(scope: Construct, id: string, props: RouteAttributes) { - super(scope, id); - - if (props.routeArn) { - this.routeArn = props.routeArn; - this.routeName = cdk.Fn.select(4, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.routeArn).resourceName!)); - } else if (props.routeName && props.meshName && props.virtualRouterName) { - this.routeName = props.routeName; - this.routeArn = cdk.Stack.of(this).formatArn({ - service: 'appmesh', - resource: `mesh/${props.meshName}/virtualRouter/${props.virtualRouterName}/route`, - resourceName: this.routeName, - }); - } else { - throw new Error('Need either arn or three names'); - } - } + readonly virtualRouter: IVirtualRouter; } diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway.ts index 51950f82dbb13..337807c9153da 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway.ts @@ -26,7 +26,7 @@ export interface IVirtualGateway extends cdk.IResource { readonly virtualGatewayArn: string; /** - * The mesh which the VirtualGateway belongs to + * The Mesh which the VirtualGateway belongs to */ readonly mesh: IMesh; @@ -67,7 +67,7 @@ export interface VirtualGatewayBaseProps { */ export interface VirtualGatewayProps extends VirtualGatewayBaseProps { /** - * The mesh which the VirtualGateway belongs to + * The Mesh which the VirtualGateway belongs to */ readonly mesh: IMesh; } @@ -84,7 +84,7 @@ abstract class VirtualGatewayBase extends cdk.Resource implements IVirtualGatewa public abstract readonly virtualGatewayArn: string; /** - * The name of the mesh which the VirtualGateway belongs to + * The Mesh which the VirtualGateway belongs to */ public abstract readonly mesh: IMesh; @@ -112,7 +112,27 @@ export class VirtualGateway extends VirtualGatewayBase { * Import an existing VirtualGateway given an ARN */ public static fromVirtualGatewayArn(scope: Construct, id: string, virtualGatewayArn: string): IVirtualGateway { - return new ImportedVirtualGateway(scope, id, { virtualGatewayArn }); + return new class extends VirtualGatewayBase { + private readonly parsedArn = cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(virtualGatewayArn).resourceName!); + readonly mesh = Mesh.fromMeshName(this, 'Mesh', cdk.Fn.select(0, this.parsedArn)); + readonly virtualGatewayArn = virtualGatewayArn; + readonly virtualGatewayName = cdk.Fn.select(2, this.parsedArn); + }(scope, id); + } + + /** + * Import an existing VirtualGateway given its attributes + */ + public static fromVirtualGatewayAttributes(scope: Construct, id: string, attrs: VirtualGatewayAttributes): IVirtualGateway { + return new class extends VirtualGatewayBase { + readonly mesh = attrs.mesh; + readonly virtualGatewayName = attrs.virtualGatewayName; + readonly virtualGatewayArn = cdk.Stack.of(this).formatArn({ + service: 'appmesh', + resource: `mesh/${attrs.mesh.meshName}/virtualGateway`, + resourceName: this.virtualGatewayName, + }); + }(scope, id); } /** @@ -171,56 +191,14 @@ export class VirtualGateway extends VirtualGatewayBase { /** * Unterface with properties necessary to import a reusable VirtualGateway */ -interface VirtualGatewayAttributes { - /** - * The name of the VirtualGateway - */ - readonly virtualGatewayName?: string; - - /** - * The Amazon Resource Name (ARN) belonging to the VirtualGateway - */ - readonly virtualGatewayArn?: string; - - /** - * The Mesh that the VirtualGateway belongs to - */ - readonly mesh?: IMesh; - - /** - * The name of the mesh that the VirtualGateway belongs to - */ - readonly meshName?: string; -} - -/** - * Used to import a VirtualGateway and read its properties - */ -class ImportedVirtualGateway extends VirtualGatewayBase { +export interface VirtualGatewayAttributes { /** * The name of the VirtualGateway */ - public readonly virtualGatewayName: string; - - /** - * The Amazon Resource Name (ARN) belonging to the VirtualGateway - */ - public readonly virtualGatewayArn: string; + readonly virtualGatewayName: string; /** * The Mesh that the VirtualGateway belongs to */ - public readonly mesh: IMesh; - - constructor(scope: Construct, id: string, props: VirtualGatewayAttributes) { - super(scope, id); - if (props.virtualGatewayArn) { - const meshName = cdk.Fn.select(0, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.virtualGatewayArn).resourceName!)); - this.mesh = Mesh.fromMeshName(this, 'Mesh', meshName); - this.virtualGatewayArn = props.virtualGatewayArn; - this.virtualGatewayName = cdk.Fn.select(2, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.virtualGatewayArn).resourceName!)); - } else { - throw new Error('Need virtualGatewayArn'); - } - } + readonly mesh: IMesh; } diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts index c3226a61e3813..b8b9da2026715 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts @@ -2,7 +2,7 @@ import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnVirtualNode } from './appmesh.generated'; -import { IMesh } from './mesh'; +import { IMesh, Mesh } from './mesh'; import { validateHealthChecks } from './private/utils'; import { AccessLog, HealthCheck, PortMapping, Protocol, VirtualNodeListener } from './shared-interfaces'; import { IVirtualService } from './virtual-service'; @@ -19,7 +19,7 @@ export interface IVirtualNode extends cdk.IResource { readonly virtualNodeName: string; /** - * The Amazon Resource Name belonging to the VirtualNdoe + * The Amazon Resource Name belonging to the VirtualNode * * Set this value as the APPMESH_VIRTUAL_NODE_NAME environment variable for * your task group's Envoy proxy container in your task definition or pod @@ -29,6 +29,11 @@ export interface IVirtualNode extends cdk.IResource { */ readonly virtualNodeArn: string; + /** + * The Mesh which the VirtualNode belongs to + */ + readonly mesh: IMesh; + /** * Utility method to add backends for existing or new VirtualNodes */ @@ -105,7 +110,7 @@ export interface VirtualNodeBaseProps { */ export interface VirtualNodeProps extends VirtualNodeBaseProps { /** - * The name of the AppMesh which the virtual node belongs to + * The Mesh which the VirtualNode belongs to */ readonly mesh: IMesh; } @@ -117,15 +122,20 @@ abstract class VirtualNodeBase extends cdk.Resource implements IVirtualNode { public abstract readonly virtualNodeName: string; /** - * The Amazon Resource Name belonging to the VirtualNdoe + * The Amazon Resource Name belonging to the VirtualNode */ public abstract readonly virtualNodeArn: string; + /** + * The Mesh which the VirtualNode belongs to + */ + public abstract readonly mesh: IMesh; + protected readonly backends = new Array(); protected readonly listeners = new Array(); /** - * Add a Virtual Services that this node is expected to send outbound traffic to + * Add a VirtualServices that this node is expected to send outbound traffic to */ public addBackends(...props: IVirtualService[]) { for (const s of props) { @@ -197,17 +207,27 @@ export class VirtualNode extends VirtualNodeBase { * Import an existing VirtualNode given an ARN */ public static fromVirtualNodeArn(scope: Construct, id: string, virtualNodeArn: string): IVirtualNode { - return new ImportedVirtualNode(scope, id, { virtualNodeArn }); + return new class extends VirtualNodeBase { + readonly virtualNodeArn = virtualNodeArn; + private readonly parsedArn = cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(virtualNodeArn).resourceName!); + readonly mesh = Mesh.fromMeshName(this, 'Mesh', cdk.Fn.select(0, this.parsedArn)); + readonly virtualNodeName = cdk.Fn.select(2, this.parsedArn); + }(scope, id); } /** * Import an existing VirtualNode given its name */ - public static fromVirtualNodeName(scope: Construct, id: string, meshName: string, virtualNodeName: string): IVirtualNode { - return new ImportedVirtualNode(scope, id, { - meshName, - virtualNodeName, - }); + public static fromVirtualNodeAttributes(scope: Construct, id: string, attrs: VirtualNodeAttributes): IVirtualNode { + return new class extends VirtualNodeBase { + readonly mesh = attrs.mesh; + readonly virtualNodeName = attrs.virtualNodeName; + readonly virtualNodeArn = cdk.Stack.of(this).formatArn({ + service: 'appmesh', + resource: `mesh/${attrs.mesh.meshName}/virtualNode`, + resourceName: this.virtualNodeName, + }); + }(scope, id); } /** @@ -221,7 +241,7 @@ export class VirtualNode extends VirtualNodeBase { public readonly virtualNodeArn: string; /** - * The service mesh that the virtual node resides in + * The Mesh which the VirtualNode belongs to */ public readonly mesh: IMesh; @@ -271,54 +291,16 @@ function renderAttributes(attrs?: {[key: string]: string}) { } /** - * Interface with properties ncecessary to import a reusable VirtualNode - */ -interface VirtualNodeAttributes { - /** - * The name of the VirtualNode - */ - readonly virtualNodeName?: string; - - /** - * The Amazon Resource Name belonging to the VirtualNdoe - */ - readonly virtualNodeArn?: string; - - /** - * The service mesh that the virtual node resides in - */ - readonly meshName?: string; -} - -/** - * Used to import a VirtualNode and read its properties + * Interface with properties necessary to import a reusable VirtualNode */ -class ImportedVirtualNode extends VirtualNodeBase { +export interface VirtualNodeAttributes { /** * The name of the VirtualNode */ - public readonly virtualNodeName: string; + readonly virtualNodeName: string; /** - * The Amazon Resource Name belonging to the VirtualNdoe + * The Mesh that the VirtualNode belongs to */ - public readonly virtualNodeArn: string; - - constructor(scope: Construct, id: string, props: VirtualNodeAttributes) { - super(scope, id); - - if (props.virtualNodeArn) { - this.virtualNodeArn = props.virtualNodeArn; - this.virtualNodeName = cdk.Fn.select(2, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.virtualNodeArn).resourceName!)); - } else if (props.virtualNodeName && props.meshName) { - this.virtualNodeName = props.virtualNodeName; - this.virtualNodeArn = cdk.Stack.of(this).formatArn({ - service: 'appmesh', - resource: `mesh/${props.meshName}/virtualNode`, - resourceName: this.virtualNodeName, - }); - } else { - throw new Error('Need either arn or both names'); - } - } + readonly mesh: IMesh; } diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts index f08b223ec23ed..2b416427ae389 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts @@ -24,7 +24,7 @@ export interface IVirtualRouter extends cdk.IResource { readonly virtualRouterArn: string; /** - * The service mesh that the virtual router resides in + * The Mesh which the VirtualRouter belongs to */ readonly mesh: IMesh; @@ -39,7 +39,7 @@ export interface IVirtualRouter extends cdk.IResource { */ export interface VirtualRouterBaseProps { /** - * Listener specification for the virtual router + * Listener specification for the VirtualRouter * * @default - A listener on HTTP port 8080 */ @@ -58,7 +58,7 @@ export interface VirtualRouterBaseProps { */ export interface Listener { /** - * Listener port for the virtual router + * Listener port for the VirtualRouter */ readonly portMapping: PortMapping; } @@ -75,7 +75,7 @@ abstract class VirtualRouterBase extends cdk.Resource implements IVirtualRouter public abstract readonly virtualRouterArn: string; /** - * The AppMesh mesh the VirtualRouter belongs to + * The Mesh which the VirtualRouter belongs to */ public abstract readonly mesh: IMesh; @@ -95,11 +95,11 @@ abstract class VirtualRouterBase extends cdk.Resource implements IVirtualRouter } /** - * The properties used when creating a new VritualRouter + * The properties used when creating a new VirtualRouter */ export interface VirtualRouterProps extends VirtualRouterBaseProps { /** - * The AppMesh mesh the VirtualRouter belongs to + * The Mesh which the VirtualRouter belongs to */ readonly mesh: IMesh; } @@ -109,21 +109,27 @@ export class VirtualRouter extends VirtualRouterBase { * Import an existing VirtualRouter given an ARN */ public static fromVirtualRouterArn(scope: Construct, id: string, virtualRouterArn: string): IVirtualRouter { - return new ImportedVirtualRouter(scope, id, { virtualRouterArn }); + return new class extends VirtualRouterBase { + readonly virtualRouterArn = virtualRouterArn; + private readonly parsedArn = cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(virtualRouterArn).resourceName!); + readonly virtualRouterName = cdk.Fn.select(2, this.parsedArn); + readonly mesh = Mesh.fromMeshName(this, 'Mesh', cdk.Fn.select(0, this.parsedArn)); + }(scope, id); } /** - * Import an existing VirtualRouter given names - */ - public static fromVirtualRouterName(scope: Construct, id: string, meshName: string, virtualRouterName: string): IVirtualRouter { - return new ImportedVirtualRouter(scope, id, { meshName, virtualRouterName }); - } - - /** - * Import an existing virtual router given attributes + * Import an existing VirtualRouter given attributes */ public static fromVirtualRouterAttributes(scope: Construct, id: string, attrs: VirtualRouterAttributes): IVirtualRouter { - return new ImportedVirtualRouter(scope, id, attrs); + return new class extends VirtualRouterBase { + readonly virtualRouterName = attrs.virtualRouterName; + readonly mesh = attrs.mesh; + readonly virtualRouterArn = cdk.Stack.of(this).formatArn({ + service: 'appmesh', + resource: `mesh/${attrs.mesh.meshName}/virtualRouter`, + resourceName: this.virtualRouterName, + }); + }(scope, id); } /** @@ -137,7 +143,7 @@ export class VirtualRouter extends VirtualRouterBase { public readonly virtualRouterArn: string; /** - * The AppMesh mesh the VirtualRouter belongs to + * The Mesh which the VirtualRouter belongs to */ public readonly mesh: IMesh; @@ -185,75 +191,10 @@ export interface VirtualRouterAttributes { /** * The name of the VirtualRouter */ - readonly virtualRouterName?: string; - - /** - * The Amazon Resource Name (ARN) for the VirtualRouter - */ - readonly virtualRouterArn?: string; - - /** - * The AppMesh mesh the VirtualRouter belongs to - */ - readonly mesh?: IMesh; - - /** - * The name of the AppMesh mesh the VirtualRouter belongs to - */ - readonly meshName?: string; -} - -/** - * Used to import a VirtualRouter and perform actions or read properties from - */ -class ImportedVirtualRouter extends VirtualRouterBase { - /** - * The name of the VirtualRouter - */ - public readonly virtualRouterName: string; - - /** - * The Amazon Resource Name (ARN) for the VirtualRouter - */ - public readonly virtualRouterArn: string; - - private _mesh?: IMesh; - - constructor(scope: Construct, id: string, props: VirtualRouterAttributes) { - super(scope, id); - - if (props.mesh) { - this._mesh = props.mesh; - } - if (props.meshName) { - if (props.mesh) { - throw new Error('Supply either \'mesh\' or \'meshName\', but not both'); - } - this._mesh = Mesh.fromMeshName(this, 'Mesh', props.meshName); - } - - if (props.virtualRouterArn) { - this.virtualRouterArn = props.virtualRouterArn; - this.virtualRouterName = cdk.Fn.select(2, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.virtualRouterArn).resourceName!)); - } else if (props.virtualRouterName && props.meshName) { - this.virtualRouterName = props.virtualRouterName; - this.virtualRouterArn = cdk.Stack.of(this).formatArn({ - service: 'appmesh', - resource: `mesh/${props.meshName}/virtualRouter`, - resourceName: this.virtualRouterName, - }); - } else { - throw new Error('Need either arn or both names'); - } - } + readonly virtualRouterName: string; /** - * The AppMesh mesh the VirtualRouter belongs to + * The Mesh which the VirtualRouter belongs to */ - public get mesh(): IMesh { - if (!this._mesh) { - throw new Error('Please supply either \'mesh\' or \'meshName\' when calling \'fromVirtualRouterAttributes\''); - } - return this._mesh; - } + readonly mesh: IMesh; } diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts index 9b920ea36c9b5..374d342040784 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts @@ -1,7 +1,7 @@ import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnVirtualService } from './appmesh.generated'; -import { IMesh } from './mesh'; +import { IMesh, Mesh } from './mesh'; import { IVirtualNode } from './virtual-node'; import { IVirtualRouter } from './virtual-router'; @@ -22,6 +22,11 @@ export interface IVirtualService extends cdk.IResource { * @attribute */ readonly virtualServiceArn: string; + + /** + * The Mesh which the VirtualService belongs to + */ + readonly mesh: IMesh; } /** @@ -59,7 +64,7 @@ export interface VirtualServiceBaseProps { */ export interface VirtualServiceProps extends VirtualServiceBaseProps { /** - * The AppMesh mesh name for which the VirtualService belongs to + * The Mesh which the VirtualService belongs to */ readonly mesh: IMesh; } @@ -76,19 +81,27 @@ export class VirtualService extends cdk.Resource implements IVirtualService { * Import an existing VirtualService given an ARN */ public static fromVirtualServiceArn(scope: Construct, id: string, virtualServiceArn: string): IVirtualService { - return new ImportedVirtualService(scope, id, { - virtualServiceArn, - }); + return new class extends cdk.Resource implements IVirtualService { + readonly virtualServiceArn = virtualServiceArn; + private readonly parsedArn = cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(virtualServiceArn).resourceName!); + readonly virtualServiceName = cdk.Fn.select(2, this.parsedArn); + readonly mesh = Mesh.fromMeshName(this, 'Mesh', cdk.Fn.select(0, this.parsedArn)); + }(scope, id); } /** - * Import an existing VirtualService given mesh and service names + * Import an existing VirtualService given its attributes */ - public static fromVirtualServiceName(scope: Construct, id: string, meshName: string, virtualServiceName: string): IVirtualService { - return new ImportedVirtualService(scope, id, { - meshName, - virtualServiceName, - }); + public static fromVirtualServiceAttributes(scope: Construct, id: string, attrs: VirtualServiceAttributes): IVirtualService { + return new class extends cdk.Resource implements IVirtualService { + readonly virtualServiceName = attrs.virtualServiceName; + readonly mesh = attrs.mesh; + readonly virtualServiceArn = cdk.Stack.of(this).formatArn({ + service: 'appmesh', + resource: `mesh/${attrs.mesh.meshName}/virtualService`, + resourceName: this.virtualServiceName, + }); + }(scope, id); } /** @@ -101,8 +114,12 @@ export class VirtualService extends cdk.Resource implements IVirtualService { */ public readonly virtualServiceArn: string; + /** + * The Mesh which the VirtualService belongs to + */ + public readonly mesh: IMesh; + private readonly virtualServiceProvider?: CfnVirtualService.VirtualServiceProviderProperty; - private readonly mesh: IMesh; constructor(scope: Construct, id: string, props: VirtualServiceProps) { super(scope, id, { @@ -159,60 +176,14 @@ export class VirtualService extends cdk.Resource implements IVirtualService { /** * Interface with properties ncecessary to import a reusable VirtualService */ -interface VirtualServiceAttributes { - /** - * The Amazon Resource Name (ARN) for the virtual service - * - * @default - Required if virtualServiceName and virtualMeshName are not supplied. - */ - readonly virtualServiceArn?: string; - +export interface VirtualServiceAttributes { /** * The name of the VirtualService, it is recommended this follows the fully-qualified domain name format. - * - * @default - Required if virtualServiceArn is not supplied. */ - readonly virtualServiceName?: string; - - /** - * The name of the service mesh that the virtual service resides in - * - * Used to derive ARN from mesh name if ARN not provided - * - * @default - Required if virtualServiceArn is not supplied. - */ - readonly meshName?: string; -} + readonly virtualServiceName: string; -/** - * Returns properties that allows a VirtualService to be imported - */ -class ImportedVirtualService extends cdk.Resource implements IVirtualService { /** - * The name of the VirtualService, it is recommended this follows the fully-qualified domain name format. + * The Mesh which the VirtualService belongs to */ - public readonly virtualServiceName: string; - - /** - * The Amazon Resource Name (ARN) for the virtual service - */ - public readonly virtualServiceArn: string; - - constructor(scope: Construct, id: string, props: VirtualServiceAttributes) { - super(scope, id); - - if (props.virtualServiceArn) { - this.virtualServiceArn = props.virtualServiceArn; - this.virtualServiceName = cdk.Fn.select(2, cdk.Fn.split('/', cdk.Stack.of(scope).parseArn(props.virtualServiceArn).resourceName!)); - } else if (props.virtualServiceName && props.meshName) { - this.virtualServiceName = props.virtualServiceName; - this.virtualServiceArn = cdk.Stack.of(this).formatArn({ - service: 'appmesh', - resource: `mesh/${props.meshName}/virtualService`, - resourceName: this.virtualServiceName, - }); - } else { - throw new Error('Need either arn or both names'); - } - } + readonly mesh: IMesh; } diff --git a/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts b/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts index 842e553dfa20c..2f08e58bb873a 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts @@ -133,20 +133,47 @@ export = { }, }, - 'Can export and import GatewayRoutes and perform actions'(test: Test) { + 'Can import Gateway Routes using an ARN'(test: Test) { const app = new cdk.App(); // GIVEN const stack = new cdk.Stack(app, 'Imports', { env: { account: '123456789012', region: 'us-east-1' }, }); + const meshName = 'test-mesh'; + const virtualGatewayName = 'test-gateway'; + const gatewayRouteName = 'test-gateway-route'; + const arn = `arn:aws:appmesh:us-east-1:123456789012:mesh/${meshName}/virtualGateway/${virtualGatewayName}/gatewayRoute/${gatewayRouteName}`; // WHEN - const gatewayRoute2 = appmesh.GatewayRoute.fromGatewayRouteArn( - stack, 'importedGatewayRoute2', 'arn:aws:appmesh:us-east-1:123456789012:mesh/test-mesh/virtualGateway/test-gateway/gatewayRoute/test-gateway-route'); + const gatewayRoute = appmesh.GatewayRoute.fromGatewayRouteArn(stack, 'importedGatewayRoute', arn); // THEN - test.equal(gatewayRoute2.gatewayRouteName, 'test-gateway-route'); - test.equal(gatewayRoute2.virtualGateway.virtualGatewayName, 'test-gateway'); - test.equal(gatewayRoute2.virtualGateway.mesh.meshName, 'test-mesh'); + test.equal(gatewayRoute.gatewayRouteName, gatewayRouteName); + test.equal(gatewayRoute.virtualGateway.virtualGatewayName, virtualGatewayName); + test.equal(gatewayRoute.virtualGateway.mesh.meshName, meshName); + test.done(); + }, + 'Can import Gateway Routes using attributes'(test: Test) { + const app = new cdk.App(); + // GIVEN + const stack = new cdk.Stack(app, 'Imports', { + env: { account: '123456789012', region: 'us-east-1' }, + }); + const meshName = 'test-mesh'; + const virtualGatewayName = 'test-gateway'; + const gatewayRouteName = 'test-gateway-route'; + + // WHEN + const mesh = appmesh.Mesh.fromMeshName(stack, 'Mesh', meshName); + const gateway = mesh.addVirtualGateway('VirtualGateway', { + virtualGatewayName: virtualGatewayName, + }); + const gatewayRoute = appmesh.GatewayRoute.fromGatewayRouteAttributes(stack, 'importedGatewayRoute', { + gatewayRouteName: gatewayRouteName, + virtualGateway: gateway, + }); + // THEN + test.equal(gatewayRoute.gatewayRouteName, gatewayRouteName); + test.equal(gatewayRoute.virtualGateway.mesh.meshName, meshName); test.done(); }, }; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appmesh/test/test.route.ts b/packages/@aws-cdk/aws-appmesh/test/test.route.ts index 706a29a3552fc..3f24bdf4be470 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.route.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.route.ts @@ -4,54 +4,44 @@ import { Test } from 'nodeunit'; import * as appmesh from '../lib'; export = { - 'Can export existing route and re-import'(test: Test) { + 'Can import Routes using an ARN'(test: Test) { + const app = new cdk.App(); // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const mesh = new appmesh.Mesh(stack, 'mesh', { - meshName: 'test-mesh', - }); - - const router = new appmesh.VirtualRouter(stack, 'router', { - mesh, + const stack = new cdk.Stack(app, 'Imports', { + env: { account: '123456789012', region: 'us-east-1' }, }); + const meshName = 'test-mesh'; + const virtualRouterName = 'test-virtual-router'; + const routeName = 'test-route'; + const arn = `arn:aws:appmesh:us-east-1:123456789012:mesh/${meshName}/virtualRouter/${virtualRouterName}/gatewayRoute/${routeName}`; - const service1 = new appmesh.VirtualService(stack, 'service-1', { - virtualServiceName: 'service1.domain.local', - mesh, - }); - - const node = mesh.addVirtualNode('test-node', { - dnsHostName: 'test', - listener: { - portMapping: - { - port: 8080, - protocol: appmesh.Protocol.HTTP, - }, - }, - backends: [ - service1, - ], + // WHEN + const route = appmesh.Route.fromRouteArn(stack, 'importedRoute', arn); + // THEN + test.equal(route.routeName, routeName); + test.equal(route.virtualRouter.virtualRouterName, virtualRouterName); + test.equal(route.virtualRouter.mesh.meshName, meshName); + test.done(); + }, + 'Can import Routes using ARN and attributes'(test: Test) { + const app = new cdk.App(); + // GIVEN + const stack = new cdk.Stack(app, 'Imports', { + env: { account: '123456789012', region: 'us-east-1' }, }); + const meshName = 'test-mesh'; + const virtualRouterName = 'test-virtual-router'; + const routeName = 'test-route'; - const route = new appmesh.Route(stack, 'route-1', { - mesh, - virtualRouter: router, - routeTargets: [ - { - virtualNode: node, - weight: 50, - }, - ], - prefix: '/', + // WHEN + const mesh = appmesh.Mesh.fromMeshName(stack, 'Mesh', meshName); + const virtualRouter = mesh.addVirtualRouter('VirtualGateway', { + virtualRouterName: virtualRouterName, }); - - const stack2 = new cdk.Stack(); - appmesh.Route.fromRouteName(stack2, 'imported-route', mesh.meshName, router.virtualRouterName, route.routeName); - - // Nothing to do with imported route yet + const route = appmesh.Route.fromRouteAttributes(stack, 'importedRoute', { routeName, virtualRouter }); + // THEN + test.equal(route.routeName, routeName); + test.equal(route.virtualRouter.mesh.meshName, meshName); test.done(); }, diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts index 1dd75b938ab04..f5c020426c9b9 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts @@ -238,21 +238,42 @@ export = { test.done(); }, }, - - 'Can export and import VirtualGateway and perform actions'(test: Test) { + 'Can import VirtualGateways using an ARN'(test: Test) { const app = new cdk.App(); // GIVEN const stack = new cdk.Stack(app, 'Imports', { env: { account: '123456789012', region: 'us-east-1' }, }); + const meshName = 'testMesh'; + const virtualGatewayName = 'test-gateway'; + const arn = `arn:aws:appmesh:us-east-1:123456789012:mesh/${meshName}/virtualGateway/${virtualGatewayName}`; // WHEN - const virtualGateway2 = appmesh.VirtualGateway.fromVirtualGatewayArn( - stack, 'importedGateway2', 'arn:aws:appmesh:us-east-1:123456789012:mesh/testMesh/virtualGateway/test-gateway'); + const virtualGateway = appmesh.VirtualGateway.fromVirtualGatewayArn( + stack, 'importedGateway', arn); + // THEN + test.equal(virtualGateway.mesh.meshName, meshName); + test.equal(virtualGateway.virtualGatewayName, virtualGatewayName); + test.done(); + }, + 'Can import VirtualGateways using attributes'(test: Test) { + const app = new cdk.App(); + // GIVEN + const stack = new cdk.Stack(app, 'Imports', { + env: { account: '123456789012', region: 'us-east-1' }, + }); + const meshName = 'testMesh'; + const virtualGatewayName = 'test-gateway'; + // WHEN + const virtualGateway = appmesh.VirtualGateway.fromVirtualGatewayAttributes(stack, 'importedGateway', { + mesh: appmesh.Mesh.fromMeshName(stack, 'Mesh', meshName), + virtualGatewayName: virtualGatewayName, + }); // THEN - test.equal(virtualGateway2.mesh.meshName, 'testMesh'); - test.equal(virtualGateway2.virtualGatewayName, 'test-gateway'); + test.equal(virtualGateway.mesh.meshName, meshName); + test.equal(virtualGateway.virtualGatewayName, virtualGatewayName); + test.done(); }, }; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts index 82589e2c52ac5..06928a4a25351 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts @@ -102,55 +102,36 @@ export = { }, }, }, - 'Can export and import VirtualNode and perform actions'(test: Test) { + 'Can import Virtual Nodes using an ARN'(test: Test) { // GIVEN const stack = new cdk.Stack(); - // WHEN - const mesh = new appmesh.Mesh(stack, 'mesh', { - meshName: 'test-mesh', - }); - - const node = mesh.addVirtualNode('test-node', { - dnsHostName: 'test.domain.local', - listener: {}, - }); - - const stack2 = new cdk.Stack(); + const meshName = 'testMesh'; + const virtualNodeName = 'test-node'; + const arn = `arn:aws:appmesh:us-east-1:123456789012:mesh/${meshName}/virtualNode/${virtualNodeName}`; - const node2 = appmesh.VirtualNode.fromVirtualNodeName(stack2, 'imported-node', mesh.meshName, node.virtualNodeName); + // WHEN + const virtualNode = appmesh.VirtualNode.fromVirtualNodeArn( + stack, 'importedVirtualNode', arn); + // THEN + test.equal(virtualNode.mesh.meshName, meshName); + test.equal(virtualNode.virtualNodeName, virtualNodeName); - node2.addListeners({ - portMapping: { - port: 8081, - protocol: appmesh.Protocol.TCP, - }, + test.done(); + }, + 'Can import Virtual Nodes using attributes'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const meshName = 'testMesh'; + const virtualNodeName = 'test-node'; + // WHEN + const virtualNode = appmesh.VirtualNode.fromVirtualNodeAttributes(stack, 'importedVirtualNode', { + mesh: appmesh.Mesh.fromMeshName(stack, 'Mesh', meshName), + virtualNodeName: virtualNodeName, }); - // THEN - expect(stack).to( - haveResourceLike('AWS::AppMesh::VirtualNode', { - MeshName: { - 'Fn::GetAtt': ['meshACDFE68E', 'MeshName'], - }, - Spec: { - Listeners: [ - { - PortMapping: { - Port: 8080, - Protocol: 'http', - }, - }, - ], - ServiceDiscovery: { - DNS: { - Hostname: 'test.domain.local', - }, - }, - }, - VirtualNodeName: 'meshtestnode428A9479', - }), - ); + test.equal(virtualNode.mesh.meshName, meshName); + test.equal(virtualNode.virtualNodeName, virtualNodeName); test.done(); }, diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts index 47b59e0e39962..dff7e4321f1f1 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts @@ -304,15 +304,38 @@ export = { }, }, - 'can import a virtual router'(test: Test) { + 'Can import Virtual Routers using an ARN'(test: Test) { // GIVEN const stack = new cdk.Stack(); + const meshName = 'testMesh'; + const virtualRouterName = 'virtual-router'; + const arn = `arn:aws:appmesh:us-east-1:123456789012:mesh/${meshName}/virtualRouter/${virtualRouterName}`; + // WHEN - const vr = appmesh.VirtualRouter.fromVirtualRouterName(stack, 'Router', 'MyMesh', 'MyRouter'); + const virtualRouter = appmesh.VirtualRouter.fromVirtualRouterArn( + stack, 'importedVirtualRouter', arn); + // THEN + test.equal(virtualRouter.mesh.meshName, meshName); + test.equal(virtualRouter.virtualRouterName, virtualRouterName); + test.done(); + }, + 'Can import Virtual Routers using attributes'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + const meshName = 'testMesh'; + const virtualRouterName = 'virtual-router'; + + // WHEN + const virtualRouter1 = appmesh.VirtualRouter.fromVirtualRouterAttributes(stack, 'importVirtualRouter', { + mesh: appmesh.Mesh.fromMeshName(stack, 'Mesh', meshName), + virtualRouterName: virtualRouterName, + }); // THEN - test.ok(vr.mesh !== undefined); + test.equal(virtualRouter1.mesh.meshName, meshName); + test.equal(virtualRouter1.virtualRouterName, virtualRouterName); test.done(); }, diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts index aa582c9376f19..c09c156ac75ea 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts @@ -1,39 +1,39 @@ -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as appmesh from '../lib'; export = { - 'Can export existing virtual-service and re-import'(test: Test) { + 'Can import Virtual Services using an ARN'(test: Test) { // GIVEN const stack = new cdk.Stack(); + const meshName = 'testMesh'; + const virtualServiceName = 'virtual-service'; + const arn = `arn:aws:appmesh:us-east-1:123456789012:mesh/${meshName}/virtualService/${virtualServiceName}`; // WHEN - const mesh = new appmesh.Mesh(stack, 'mesh', { - meshName: 'test-mesh', - }); + const virtualRouter = appmesh.VirtualRouter.fromVirtualRouterArn(stack, 'importedVirtualRouter', arn); + // THEN + test.equal(virtualRouter.mesh.meshName, meshName); + test.equal(virtualRouter.virtualRouterName, virtualServiceName); - const router = new appmesh.VirtualRouter(stack, 'router', { mesh }); + test.done(); + }, + 'Can import Virtual Services using attributes'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'vpc'); - const namespace = new cloudmap.PrivateDnsNamespace(stack, 'test-namespace', { - vpc, - name: 'domain.local', - }); + const meshName = 'testMesh'; + const virtualServiceName = 'virtual-service'; - const service = new appmesh.VirtualService(stack, 'service-1', { - mesh, - virtualServiceName: `service.${namespace.namespaceName}`, - virtualRouter: router, + // WHEN + const virtualService = appmesh.VirtualService.fromVirtualServiceAttributes(stack, 'importedVirtualService', { + mesh: appmesh.Mesh.fromMeshName(stack, 'Mesh', meshName), + virtualServiceName: virtualServiceName, }); - - const stack2 = new cdk.Stack(); - appmesh.VirtualService.fromVirtualServiceName(stack2, 'imported-virtual-service', mesh.meshName, service.virtualServiceName); - - // Nothing to do with imported virtual service yet - + // THEN + test.equal(virtualService.mesh.meshName, meshName); + test.equal(virtualService.virtualServiceName, virtualServiceName); test.done(); }, };