UNPKG

serverless-tag-resources

Version:

Datamart: Tag all AWS resources with dual legacy + datamart:* tag support

97 lines (84 loc) 3.7 kB
"use strict"; const { CloudFormationClient, DescribeStackResourcesCommand, } = require("@aws-sdk/client-cloudformation"); const { getClient } = require("./aws-clients"); const { buildListTags, buildDictTags } = require("./tags"); const { needsPostDeployTagging, DICT_BASED_TYPES, API_ONLY_TYPES, RELATED_TYPES } = require("./resource-classifier"); const { tagSSMParameter } = require("./post-deploy/ssm"); const { tagPinpointApp } = require("./post-deploy/pinpoint"); const { tagApiGatewayV2 } = require("./post-deploy/apigatewayv2"); const { tagRDSCluster } = require("./post-deploy/rds"); const { tagFirehoseStream } = require("./post-deploy/firehose"); const { tagEC2RelatedResources } = require("./post-deploy/ec2-related"); /** * Post-Deploy Tagger — Hook: after:deploy:deploy * * Tags resources that cannot be fully tagged in the CF template: * dict-based, API-only, and related resources. */ async function updateTagsPostDeploy(config, stackName, stackTags, stage, partition, region, log) { const cfnClient = getClient(CloudFormationClient, config); const result = await cfnClient.send( new DescribeStackResourcesCommand({ StackName: stackName }) ); const allResources = result.StackResources || []; for (const resource of allResources) { const type = resource.ResourceType; if (!needsPostDeployTagging(type)) continue; const logicalId = resource.LogicalResourceId; const listTags = buildListTags(stackTags, stage, logicalId); const dictTags = buildDictTags(stackTags, stage, logicalId); try { // Dict-based types: need API call because CF template tagging // may not fully propagate for some of these types if (DICT_BASED_TYPES.has(type)) { switch (type) { case "AWS::SSM::Parameter": await tagSSMParameter(config, resource, listTags); log(`TAGGING: post-deploy SSM Parameter ${logicalId}`); break; case "AWS::Pinpoint::App": await tagPinpointApp(config, resource, dictTags); log(`TAGGING: post-deploy Pinpoint App ${logicalId}`); break; case "AWS::ApiGatewayV2::Api": case "AWS::ApiGatewayV2::Stage": case "AWS::ApiGatewayV2::DomainName": case "AWS::ApiGatewayV2::VpcLink": await tagApiGatewayV2(config, resource, dictTags, partition, region, allResources); log(`TAGGING: post-deploy ${type} ${logicalId}`); break; // Glue and Batch are tagged in template (dict-based), no post-deploy needed } } // API-only types: not tagged in template at all if (API_ONLY_TYPES.has(type)) { switch (type) { case "AWS::RDS::DBCluster": await tagRDSCluster(config, resource, listTags, partition, region); log(`TAGGING: post-deploy RDS Cluster ${logicalId}`); break; case "AWS::KinesisFirehose::DeliveryStream": await tagFirehoseStream(config, resource, listTags); log(`TAGGING: post-deploy Firehose ${logicalId}`); break; } } // Related types: tag associated resources (volumes, ENIs, etc.) if (RELATED_TYPES.has(type)) { switch (type) { case "AWS::EC2::Instance": { const relatedIds = await tagEC2RelatedResources(config, resource, listTags); log(`TAGGING: post-deploy EC2 related resources for ${logicalId}: ${relatedIds.length} resources`); break; } } } } catch (err) { log(`TAGGING: ERROR post-deploy ${type} ${logicalId}: ${err.message}`); } } } module.exports = { updateTagsPostDeploy };