11import re
2+ import os
3+
24from collections import defaultdict
35from time import time
46
57
68import boto3
9+ from botocore .exceptions import ClientError
10+
711from datadog_lambda .metric import lambda_metric
812
913
1923
2024GET_RESOURCES_LAMBDA_FILTER = "lambda"
2125
26+ FETCH_CUSTOM_TAGS_ENV_VAR_NAME = "DD_FETCH_CUSTOM_TAGS"
27+
2228resource_tagging_client = boto3 .client ("resourcegroupstaggingapi" )
2329
2430
31+ def should_fetch_custom_tags ():
32+ """Checks the env var to determine if the customer has opted-in to fetching custom tags
33+ """
34+ env_var_value = os .environ .get (FETCH_CUSTOM_TAGS_ENV_VAR_NAME )
35+ return env_var_value and env_var_value .lower () == "true"
36+
37+
2538def sanitize_aws_tag_string (raw_string ):
2639 """Convert banned characters to underscores
2740 """
@@ -50,31 +63,63 @@ def get_dd_tag_string_from_aws_dict(aws_key_value_tag_dict):
5063 return "{}:{}" .format (key , value )
5164
5265
53- def build_arn_to_lambda_tags_cache ():
66+ def parse_get_resources_response_for_tags_by_arn (get_resources_page ):
67+ """Parses a page of GetResources response for the mapping from ARN to tags
68+
69+
70+ """
71+ tags_by_arn = defaultdict (list )
72+
73+ aws_resouce_tag_mappings = get_resources_page ["ResourceTagMappingList" ]
74+ for aws_resource_tag_mapping in aws_resouce_tag_mappings :
75+ function_arn = aws_resource_tag_mapping ["ResourceARN" ]
76+ raw_aws_tags = aws_resource_tag_mapping ["Tags" ]
77+ tags = map (get_dd_tag_string_from_aws_dict , raw_aws_tags )
78+
79+ tags_by_arn [function_arn ] += tags
80+
81+ return tags_by_arn
82+
83+
84+ def build_tags_by_arn_cache ():
5485 """Makes API calls to GetResources to get the live tags of the account's Lambda functions
5586
87+ Returns an empty dict instead of fetching custom tags if the tag fetch env variable is not set to true
88+
5689 Returns:
57- arn_to_tags_cache (dict<str, str[]>): each Lambda's tags in a dict by ARN
90+ tags_by_arn_cache (dict<str, str[]>): each Lambda's tags in a dict keyed by ARN
5891 """
59- arn_to_tags_cache = defaultdict (list )
92+ # If the custom tag fetch env var is not set to true do not fetch; return an empty dict
93+ if not should_fetch_custom_tags ():
94+ print (
95+ "Not fetching custom tags because the environment variable {} is not set to true" .format (
96+ FETCH_CUSTOM_TAGS_ENV_VAR_NAME
97+ )
98+ )
99+ return {}
100+
101+ tags_by_arn_cache = {}
60102 get_resources_paginator = resource_tagging_client .get_paginator ("get_resources" )
61103
62- for page in get_resources_paginator .paginate (
63- ResourceTypeFilters = [GET_RESOURCES_LAMBDA_FILTER ], ResourcesPerPage = 100
64- ):
65- lambda_metric (
66- "{}.get_resources_api_calls" .format (ENHANCED_METRICS_NAMESPACE_PREFIX ), 1
67- )
68- # log.info("Response from resource tagging endpoint: %s", page)
69- aws_resouce_tag_mappings = page ["ResourceTagMappingList" ]
70- for aws_resource_tag_mapping in aws_resouce_tag_mappings :
71- function_arn = aws_resource_tag_mapping ["ResourceARN" ]
72- raw_aws_tags = aws_resource_tag_mapping ["Tags" ]
73- tags = map (get_dd_tag_string_from_aws_dict , raw_aws_tags )
104+ try :
105+ for page in get_resources_paginator .paginate (
106+ ResourceTypeFilters = [GET_RESOURCES_LAMBDA_FILTER ], ResourcesPerPage = 100
107+ ):
108+ lambda_metric (
109+ "{}.get_resources_api_calls" .format (ENHANCED_METRICS_NAMESPACE_PREFIX ),
110+ 1 ,
111+ )
112+ page_tags_by_arn = parse_get_resources_response_for_tags_by_arn (page )
113+ tags_by_arn_cache .update (page_tags_by_arn )
74114
75- arn_to_tags_cache [function_arn ] += tags
115+ except ClientError as ce :
116+ print (
117+ "Encountered a ClientError when trying to fetch tags. "
118+ "You may need to give this Lambda's role permission to use the Resource Groups Tagging "
119+ "API GetResources method: {}" .format (ce )
120+ )
76121
77- return arn_to_tags_cache
122+ return tags_by_arn_cache
78123
79124
80125class LambdaTagsCache (object ):
@@ -87,7 +132,7 @@ def __init__(self, tags_ttl_seconds=3600):
87132 def _fetch_tags (self ):
88133 """Populate the tags in the cache by making calls to GetResources
89134 """
90- self .tags_by_arn = build_arn_to_lambda_tags_cache ()
135+ self .tags_by_arn = build_tags_by_arn_cache ()
91136 self .last_tags_fetch_time = time ()
92137
93138 def _are_tags_out_of_date (self ):
@@ -109,11 +154,6 @@ def get_lambda_tags(self, resource_arn):
109154 if self ._are_tags_out_of_date ():
110155 self ._fetch_tags ()
111156
112- print (
113- "Fetching tags for ARN {} with this cache: {}" .format (
114- resource_arn , self .tags_by_arn
115- )
116- )
117157 function_tags = self .tags_by_arn .get (resource_arn , [])
118158
119159 print ("Found these tags for {} ARN: {}" .format (resource_arn , function_tags ))
0 commit comments