OpenSearch过期域删除Lambda函数异常排查求助
问题排查与修正方案
你的代码核心问题在于错误解析Resource Groups Tagging API的返回结构,同时存在过滤条件冗余、ARN构造不严谨的问题,导致标签检测逻辑完全失效。以下是具体问题和修正后的代码:
关键问题点
- Tags字段结构错误理解:
get_resources返回的ResourceTagMappingList中,每个资源的Tags是键值对列表(格式为[{'Key': 'xxx', 'Value': 'xxx'}, ...]),而非字典。你的代码错误地将其当作字典调用get()方法,导致永远检测不到标签。 - 不必要的TagFilters:你用
domainName和service作为过滤条件,但OpenSearch域默认不会自动添加这两个标签,直接过滤会导致返回空列表,无法获取目标域的实际标签。 - ARN前缀兼容性:部分AWS区域中,OpenSearch域的ARN前缀应为
arn:aws:opensearch而非arn:aws:es,旧前缀可能导致标签绑定失败。 - 重复创建客户端:循环内重复创建AWS客户端,不仅低效,还可能引发不必要的API调用限制。
修正后的第一个函数(添加expiryDate标签)
import boto3 import datetime def lambda_handler(event, context): # 复用全局客户端,避免循环内重复创建 ec2_client = boto3.client('ec2', region_name='us-east-1') tagging_client = boto3.client('resourcegroupstaggingapi') sts_client = boto3.client('sts') account_id = sts_client.get_caller_identity().get('Account') regions = [region['RegionName'] for region in ec2_client.describe_regions()['Regions']] for region in regions: opensearch_client = boto3.client('opensearch', region_name=region) domains = opensearch_client.list_domain_names()['DomainNames'] for domain in domains: domain_name = domain['DomainName'] # 直接通过资源类型和名称获取标签,无需多余过滤 resources = tagging_client.get_resources( ResourceTypeFilters=['es'], ResourceARNList=[f"arn:aws:opensearch:{region}:{account_id}:domain/{domain_name}"] )['ResourceTagMappingList'] # 正确遍历标签列表,检查expiryDate是否存在 expiry_date_exists = any(tag['Key'] == 'expiryDate' for res in resources for tag in res['Tags']) if not expiry_date_exists: future_date = datetime.datetime.now() + datetime.timedelta(days=60) future_date_str = future_date.strftime('%d-%m-%Y') tagging_client.tag_resources( ResourceARNList=[f"arn:aws:opensearch:{region}:{account_id}:domain/{domain_name}"], Tags={'expiryDate': future_date_str} ) print(f"已为区域{region}的OpenSearch域{domain_name}添加expiryDate标签") else: print(f"区域{region}的OpenSearch域{domain_name}已存在expiryDate标签") return {'statusCode': 200, 'body': '所有区域OpenSearch域处理完成'}
修正后的第二个函数(删除过期域)
import boto3 import datetime def lambda_handler(event, context): ec2_client = boto3.client('ec2', region_name='us-east-1') tagging_client = boto3.client('resourcegroupstaggingapi') sts_client = boto3.client('sts') account_id = sts_client.get_caller_identity().get('Account') regions = [region['RegionName'] for region in ec2_client.describe_regions()['Regions']] for region in regions: opensearch_client = boto3.client('opensearch', region_name=region) domains = opensearch_client.list_domain_names()['DomainNames'] for domain in domains: domain_name = domain['DomainName'] resource_arn = f"arn:aws:opensearch:{region}:{account_id}:domain/{domain_name}" resources = tagging_client.get_resources( ResourceTypeFilters=['es'], ResourceARNList=[resource_arn] )['ResourceTagMappingList'] # 提取expiryDate标签值 expiry_date_str = None for res in resources: for tag in res['Tags']: if tag['Key'] == 'expiryDate': expiry_date_str = tag['Value'] break if expiry_date_str: try: expiry_date = datetime.datetime.strptime(expiry_date_str, '%d-%m-%Y') current_date = datetime.datetime.now() print(f"区域{region}的域{domain_name}过期时间:{expiry_date_str},当前时间:{current_date.strftime('%d-%m-%Y')}") if expiry_date < current_date: opensearch_client.delete_domain(DomainName=domain_name) print(f"已删除区域{region}的过期OpenSearch域{domain_name}") else: print(f"区域{region}的域{domain_name}仍在有效期内") except ValueError: print(f"区域{region}的域{domain_name}的expiryDate标签格式错误:{expiry_date_str}") else: print(f"区域{region}的域{domain_name}未找到expiryDate标签") return {'statusCode': 200, 'body': '所有区域OpenSearch域过期检查完成'}
额外建议
- 测试时分步验证:先单独运行第一个函数,然后通过AWS控制台或
aws opensearch list-tags --domain-name <域名> --region <区域>命令确认标签是否成功添加,再运行第二个函数。 - 时区问题:代码中使用本地时间(Lambda默认UTC),如果你的业务时间是其他时区,需添加时区转换逻辑,避免过期判断错误。
- 权限优化:虽然当前用了FullAdmin,但生产环境建议最小权限,为Lambda角色添加
es:ListDomainNames、es:DeleteDomain、tag:GetResources、tag:TagResources权限即可。
内容的提问来源于stack exchange,提问作者user23628798
相关产品推荐
相关产品推荐

