Applying standard/common tags on Stacks #21476
-
Hello there, Currently, all resources that we create using the CDK define their own tags at the stack level (which are then replicated on all resources of the stack, should they be compatible with). We want to go further and:
We then wish to define a standard (ie that can be used by every developer in a simple way) approach that will provide this capability. 1st approach: def apply_standard_tags(
resource: IConstruct,
env_name: str,
env_type: str,
product: Product,
domain: str,
service: str,
gov_tag: bool = False,
):
Tags.of(resource).add("Product", product.value)
Tags.of(resource).add("Domain", domain)
Tags.of(resource).add("Service", service)
Tags.of(resource).add("EnvName", env_name)
Tags.of(resource).add("EnvType", env_type)
if gov_tag:
Tags.of(resource).add("gov_tag", "1234")
class StandardTagTestStack(Stack):
def __init__(
self,
scope: Construct,
id: str,
**kwargs,
):
super().__init__(scope, id, **kwargs)
test_construct = aws_s3.Bucket(
self,
"test-bucket-name",
bucket_name="test-bucket-name",
)
apply_standard_tags(
resource=test_construct,
env_name="PR-1",
env_type="Dev",
product="Test",
domain="CleanCode",
service="website",
gov_tag=True,
)
def test_stack_tags():
cdk_app = App()
stack = StandardTagTestStack(cdk_app, "TestStack") 2nd approach: # Define a decorator that applies to a class
def gov_eligible(cls):
# Apply the mandatory tag and calls the original constructor
# Thanks to name mangling the original constructor is private
def apply_gov_tag(self, *args, **kwargs):
self.__gov_eligible_original_init_(*args, **kwargs)
Tags.of(self).add("custom", "1234")
def wrap(cls):
try:
# Replace the constructor with our wrapper that add the gov tag
cls.__gov_eligible_original_init_ = cls.__init__
cls.__init__ = apply_gov_tag
except Exception as e:
print(f"Something went wrong {str(e)}!")
return cls
# Return the same class object with a different init process
return wrap(cls)
# Define a decorator that applies to a class
def enforce_standard_tags(cls):
# Apply the custom tag and calls the original constructor
# Thanks to name mangling the original constructor is private
def apply_gov_tag(self, *args, **kwargs):
self.__standard_tags_original_init_(*args, **kwargs)
# Adopt Python protocol principle: no need for ancestor class or mixin
# to provide the required fields, their existence is enough
env_name = self.__dict__.get("_env_name", None)
env_type = self.__dict__.get("_env_type", None)
if env_name and env_type:
Tags.of(self).add("EnvName", env_name)
Tags.of(self).add("EnvType", env_type)
else:
raise ValueError("The class does not have env_name and env_type fields")
def wrap(cls):
try:
# Replace the constructor with our wrapper that add the custom tag
cls.__standard_tags_original_init_ = cls.__init__
cls.__init__ = apply_gov_tag
except Exception as e:
print(f"Something went wrong {str(e)}!")
return cls
# Return the same class object with a different init process
return wrap(cls)
@gov_eligible
@enforce_standard_tags
class MyStack(Stack):
def __init__(
self,
scope: constructs.Construct,
id: str,
env_name: str = None,
env_type: str = None,
**kwargs,
) -> None:
super().__init__(scope, id, **kwargs)
self._env_name, self._env_type = env_name, env_type
self._build_param()
self._apply_tags()
def _build_param(self):
aws_ssm.StringParameter(
self,
"VPCParameter",
description=f"VPC and env name {self._env_name}",
parameter_name="P",
string_value="1",
)
def _apply_tags(self):
Tags.of(self).add("Exotic", "Mango") |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
This sounds like an awesome feature that would have wide benefits to customers. Doing this in a consistent manner, however, is a different story all together. I have three basic suggestions:
Currently, options 1 & 2 are the ones that will get you the most broad adoption. Using jsii + typescript to create an Aspect that assures tagging also allows for Annotations, adding errors and helpful information during synthesis. |
Beta Was this translation helpful? Give feedback.
-
Hello! Reopening this discussion to make it searchable. |
Beta Was this translation helpful? Give feedback.
This sounds like an awesome feature that would have wide benefits to customers. Doing this in a consistent manner, however, is a different story all together.
I have three basic suggestions: