cloudformation-coverage-roadmap
cloudformation-coverage-roadmap copied to clipboard
[AWS::ECS::Service] - [Enhancement] - Expose Cloud Map service ARN for an ECS service using Service Connect
trafficstars
Name of the resource
AWS::ECS::Service
Resource name
No response
Description
When using ECS Service Connect, SC implicitly creates a Cloud Map service. We need the Cloud Map serivce ARN when integrating it with other AWS services like API Gateway (CloudMap integration). It would be great if CFn directly exposes the ARN as a resource attribute.
Other Details
Current workaround: use a custom resource to get the ARN. CDK example is the following:
const cluster = new Cluster(this, 'Cluster', {
defaultCloudMapNamespace: {
name: 'foo',
useForServiceConnect: true,
type: NamespaceType.HTTP,
},
});
const serviceName = 'foo-service';
const service = new ecs.FargateService(this, 'FargateService', {
cluster,
taskDefinition,
serviceConnectConfiguration: {
services: [
{
portMappingName: serviceName,
},
],
},
});
service.node.addDependency(cluster.defaultCloudMapNamespace!);
const handler = new Function(this, 'GetCloudMapServiceArn', {
runtime: Runtime.NODEJS_20_X,
handler: 'index.handler',
timeout: Duration.seconds(30),
code: Code.fromInline(`
const response = require('cfn-response');
const sdk = require('@aws-sdk/client-servicediscovery');
const client = new sdk.ServiceDiscoveryClient();
exports.handler = async function (event, context) {
try {
console.log(event);
if (event.RequestType == 'Delete') {
return await response.send(event, context, response.SUCCESS);
}
// https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/servicediscovery/command/ListServicesCommand/
const namespaceId = event.ResourceProperties.NamespaceId;
const serviceName = event.ResourceProperties.ServiceName;
const command = new sdk.ListServicesCommand({
Filters: [
{
Name: "NAMESPACE_ID",
Values: [
namespaceId,
],
Condition: "EQ",
},
],
});
const res = await client.send(command);
const service = res.Services.find(service => service.Name == serviceName);
if (service == null) {
throw new Error('Service not found.');
}
await response.send(event, context, response.SUCCESS, { serviceArn: service.Arn }, service.Id);
} catch (e) {
console.log(e);
await response.send(event, context, response.FAILED);
}
};
`),
});
handler.addToRolePolicy(
new PolicyStatement({
actions: ['servicediscovery:ListServices'],
resources: ['*'],
})
);
const resource = new CustomResource(this, `GetServiceArnResult-${serviceName}`, {
serviceToken: handler.functionArn,
resourceType: 'Custom::GetServiceArn',
properties: { NamespaceId: cluster.defaultCloudMapNamespace!.namespaceId, ServiceName: serviceName },
});
resource.node.addDependency(ecsService);
const serviceArn = resource.getAttString('serviceArn');