diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json index bd9224e586933..04e3fb87689fa 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json @@ -3185,22 +3185,12 @@ "Backends": [ { "VirtualService": { - "VirtualServiceName": { - "Fn::GetAtt": [ - "namevirtualservice3DDDDF1E", - "VirtualServiceName" - ] - } + "VirtualServiceName": "name.production" } }, { "VirtualService": { - "VirtualServiceName": { - "Fn::GetAtt": [ - "greetingvirtualservice60AD3AD9", - "VirtualServiceName" - ] - } + "VirtualServiceName": "greeting.production" } } ], diff --git a/packages/@aws-cdk/aws-appmesh/README.md b/packages/@aws-cdk/aws-appmesh/README.md index 54bc79fade4c3..d168d56c73a7e 100644 --- a/packages/@aws-cdk/aws-appmesh/README.md +++ b/packages/@aws-cdk/aws-appmesh/README.md @@ -236,6 +236,24 @@ The `backends` property can be added with `node.addBackend()`. In the example, w The `backendDefaults` property is added to the node while creating the virtual node. These are the virtual node's default settings for all backends. +The `VirtualNode.addBackend()` method is especially useful if you want to create a circular traffic flow by having a Virtual Service as a backend whose provider is that same Virtual Node: + +```ts +declare const mesh: appmesh.Mesh; + +const node = new appmesh.VirtualNode(this, 'node', { + mesh, + serviceDiscovery: appmesh.ServiceDiscovery.dns('node'), +}); + +const virtualService = new appmesh.VirtualService(this, 'service-1', { + virtualServiceProvider: appmesh.VirtualServiceProvider.virtualNode(node), + virtualServiceName: 'service1.domain.local', +}); + +node.addBackend(appmesh.Backend.virtualService(virtualService)); +``` + ### Adding TLS to a listener The `tls` property specifies TLS configuration when creating a listener for a virtual node or a virtual gateway. diff --git a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts index 8e672ac535bdc..7598ac959e98b 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts @@ -238,7 +238,14 @@ class VirtualServiceBackend extends Backend { return { virtualServiceBackend: { virtualService: { - virtualServiceName: this.virtualService.virtualServiceName, + /** + * We want to use the name of the Virtual Service here directly instead of + * a `{ 'Fn::GetAtt' }` CFN expression. This avoids a circular dependency in + * the case where this Virtual Node is the Virtual Service's provider. + */ + virtualServiceName: cdk.Token.isUnresolved(this.virtualService.virtualServiceName) + ? (this.virtualService as any).physicalName + : this.virtualService.virtualServiceName, clientPolicy: this.tlsClientPolicy ? { tls: renderTlsClientPolicy(scope, this.tlsClientPolicy), diff --git a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json index 4b6c3e54f543e..3649195cf9c7e 100644 --- a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json +++ b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json @@ -1040,22 +1040,12 @@ "Backends": [ { "VirtualService": { - "VirtualServiceName": { - "Fn::GetAtt": [ - "service6D174F83", - "VirtualServiceName" - ] - } + "VirtualServiceName": "service1.domain.local" } }, { "VirtualService": { - "VirtualServiceName": { - "Fn::GetAtt": [ - "service27C65CF7D", - "VirtualServiceName" - ] - } + "VirtualServiceName": "service2.domain.local" } } ], @@ -1111,12 +1101,7 @@ "Backends": [ { "VirtualService": { - "VirtualServiceName": { - "Fn::GetAtt": [ - "service3859EB104", - "VirtualServiceName" - ] - } + "VirtualServiceName": "service3.domain.local" } } ], @@ -1241,12 +1226,7 @@ "Backends": [ { "VirtualService": { - "VirtualServiceName": { - "Fn::GetAtt": [ - "service4983B61EE", - "VirtualServiceName" - ] - } + "VirtualServiceName": "service4.domain.local" } } ], diff --git a/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts b/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts index f30d1562416da..294701e0d550a 100644 --- a/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/mesh.test.ts @@ -314,9 +314,7 @@ describe('mesh', () => { Backends: [ { VirtualService: { - VirtualServiceName: { - 'Fn::GetAtt': ['service1A48078CF', 'VirtualServiceName'], - }, + VirtualServiceName: 'service1.domain.local', }, }, ], diff --git a/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts b/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts index 82bc98c6267ef..842c061f68a15 100644 --- a/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts +++ b/packages/@aws-cdk/aws-appmesh/test/virtual-node.test.ts @@ -41,24 +41,18 @@ describe('virtual node', () => { Backends: [ { VirtualService: { - VirtualServiceName: { - 'Fn::GetAtt': ['service1A48078CF', 'VirtualServiceName'], - }, + VirtualServiceName: 'service1.domain.local', }, }, { VirtualService: { - VirtualServiceName: { - 'Fn::GetAtt': ['service27C65CF7D', 'VirtualServiceName'], - }, + VirtualServiceName: 'service2.domain.local', }, }, ], }, MeshOwner: ABSENT, }); - - }); }); @@ -458,9 +452,7 @@ describe('virtual node', () => { Backends: [ { VirtualService: { - VirtualServiceName: { - 'Fn::GetAtt': ['service1A48078CF', 'VirtualServiceName'], - }, + VirtualServiceName: 'service1.domain.local', ClientPolicy: { TLS: { Ports: [8080, 8081], @@ -478,8 +470,75 @@ describe('virtual node', () => { ], }, }); + }); + + test('you can add a Virtual Service as a backend to a Virtual Node which is the provider for that Virtual Service', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + const node = new appmesh.VirtualNode(stack, 'test-node', { + mesh, + serviceDiscovery: appmesh.ServiceDiscovery.dns('test'), + }); + + const myVirtualService = new appmesh.VirtualService(stack, 'service-1', { + virtualServiceProvider: appmesh.VirtualServiceProvider.virtualNode(node), + virtualServiceName: 'service1.domain.local', + }); + + node.addBackend(appmesh.Backend.virtualService(myVirtualService)); + + // THEN + expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Spec: { + Backends: [ + { + VirtualService: { + VirtualServiceName: 'service1.domain.local', + }, + }, + ], + }, + }); + }); + + test('you can add a Virtual Service with an automated name as a backend to a Virtual Node which is the provider for that Virtual Service, ', () => { + // GIVEN + const stack = new cdk.Stack(); + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + const node = new appmesh.VirtualNode(stack, 'test-node', { + mesh, + serviceDiscovery: appmesh.ServiceDiscovery.dns('test'), + }); + + const myVirtualService = new appmesh.VirtualService(stack, 'service-1', { + virtualServiceProvider: appmesh.VirtualServiceProvider.virtualNode(node), + }); + + node.addBackend(appmesh.Backend.virtualService(myVirtualService)); + + // THEN + expect(stack).toHaveResourceLike('AWS::AppMesh::VirtualNode', { + Spec: { + Backends: [ + { + VirtualService: { + VirtualServiceName: 'service1', + }, + }, + ], + }, + }); }); });