You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenSearch过期域删除Lambda函数异常排查求助

问题排查与修正方案

你的代码核心问题在于错误解析Resource Groups Tagging API的返回结构,同时存在过滤条件冗余、ARN构造不严谨的问题,导致标签检测逻辑完全失效。以下是具体问题和修正后的代码:

关键问题点

  1. Tags字段结构错误理解:get_resources返回的ResourceTagMappingList中,每个资源的Tags是键值对列表(格式为[{'Key': 'xxx', 'Value': 'xxx'}, ...]),而非字典。你的代码错误地将其当作字典调用get()方法,导致永远检测不到标签。
  2. 不必要的TagFilters:你用domainName和service作为过滤条件,但OpenSearch域默认不会自动添加这两个标签,直接过滤会导致返回空列表,无法获取目标域的实际标签。
  3. ARN前缀兼容性:部分AWS区域中,OpenSearch域的ARN前缀应为arn:aws:opensearch而非arn:aws:es,旧前缀可能导致标签绑定失败。
  4. 重复创建客户端:循环内重复创建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域过期检查完成'}

额外建议

  1. 测试时分步验证:先单独运行第一个函数,然后通过AWS控制台或aws opensearch list-tags --domain-name <域名> --region <区域>命令确认标签是否成功添加,再运行第二个函数。
  2. 时区问题:代码中使用本地时间(Lambda默认UTC),如果你的业务时间是其他时区,需添加时区转换逻辑,避免过期判断错误。
  3. 权限优化:虽然当前用了FullAdmin,但生产环境建议最小权限,为Lambda角色添加es:ListDomainNames、es:DeleteDomain、tag:GetResources、tag:TagResources权限即可。

内容的提问来源于stack exchange,提问作者user23628798

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:24:55