cloudformation-coverage-roadmap icon indicating copy to clipboard operation
cloudformation-coverage-roadmap copied to clipboard

[AWS::ECS::Service] - [Enhancement] - Expose Cloud Map service ARN for an ECS service using Service Connect

Open tmokmss opened this issue 1 year ago • 0 comments
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');

tmokmss avatar Aug 06 '24 01:08 tmokmss