Moto模拟CloudFormation创建堆栈时AWS::SNS::Subscription未生成的问题咨询
我来帮你分析下可能的原因和排查步骤,你可以逐一尝试:
1. 先确认堆栈是否完全创建完成,订阅资源是否真的被触发创建
Moto的CloudFormation模拟虽然是同步的,但有时候资源创建的事件可能需要确认状态。你可以先检查堆栈的状态,以及堆栈事件里有没有订阅资源的创建记录:
import boto3 cfn = boto3.client('cloudformation') # 检查堆栈状态 stack_info = cfn.describe_stacks(StackName="test-stack-1")['Stacks'][0] print(f"堆栈状态: {stack_info['StackStatus']}") # 查看所有堆栈事件,找订阅资源的状态 events = cfn.describe_stack_events(StackName="test-stack-1") for event in reversed(events['StackEvents']): if event['LogicalResourceId'] == 'SQSToSNSSubscription': print(f"订阅资源状态: {event['ResourceStatus']} - {event.get('ResourceStatusReason', '无备注')}")
如果看到订阅资源的状态是CREATE_FAILED,那就能直接定位问题原因;如果压根没找到这个资源的事件,那可能是CloudFormation模板的解析有问题。
2. 尝试移除Serverless Transform
你的模板里用了AWS::Serverless-2016-10-31这个Transform,但你的资源都是基础的AWS服务(DynamoDB、SNS、SQS),完全不需要依赖Serverless Transform。这个Transform可能会对资源的创建逻辑做额外处理,而Moto对这个Transform的支持可能存在疏漏。
你可以把模板里的Transform段删掉,重新创建堆栈试试:
# 删掉这段 # Transform: # - AWS::Serverless-2016-10-31
3. 检查Moto版本并升级
虽然你说没找到文档说明不支持,但Moto的某些旧版本可能确实存在CloudFormation创建SNS订阅的bug。建议升级到最新稳定版再测试:
pip install --upgrade moto
4. 对比手动创建订阅的情况
你可以手动用SNS客户端创建相同的订阅,看看是否能正常出现在list_subscriptions的结果里,以此排除是SNS模拟本身的问题:
import boto3 sns = boto3.client('sns') sqs = boto3.client('sqs') # 获取已创建的主题和队列信息 topic_arn = sns.list_topics()['Topics'][0]['TopicArn'] queue_url = sqs.get_queue_url(QueueName="test-queue")['QueueUrl'] queue_arn = sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=['QueueArn'])['Attributes']['QueueArn'] # 手动创建订阅 response = sns.subscribe( TopicArn=topic_arn, Protocol='sqs', Endpoint=queue_arn, RawMessageDelivery=True ) # 查看订阅 print("手动创建的订阅:", sns.list_subscriptions())
如果手动创建能正常查到订阅,但CloudFormation创建不行,那基本可以确定是Moto对AWS::SNS::Subscription的CloudFormation资源支持存在问题,这时候你可以去Moto的GitHub仓库提交Issue,附上你的模板和测试代码,让官方修复。
5. 检查模板里的订阅参数是否正确
你的模板里的订阅参数看起来是对的,但可以再确认下:
Endpoint用Fn::GetAtt: SQSQueue.Arn是正确的,因为SQS的Arn必须通过GetAtt获取Protocol设为sqs没问题RawMessageDelivery: true也是合法参数
暂时想到这些方向,你可以先从检查堆栈状态和移除Transform开始排查,应该能找到问题所在。
备注:内容来源于stack exchange,提问作者Martin Macak

