Ruby Psych转换YAML时!Ref/!GetAtt被加引号致CloudFormation校验失败
问题根因
这个问题的核心原因是把YAML自定义标签当成了普通字符串传入哈希:Psych序列化时会检测字符串里的YAML特殊字符,!作为自定义标签的起始标记属于特殊字符,为了保证序列化结果反序列化时语义不变,Psych会自动给这类字符串包裹双引号做转义,根本不会把它解析成自定义标签节点。同理${AWS::AccountId}被加引号,也是因为Psych默认对含特殊语法特征的字符串做安全转义,避免解析歧义。
解决方案
不要把CloudFormation的自定义标签写成普通字符串,通过Psych提供的自定义标量能力声明标签节点即可,有两种稳定实现方式:
方式1:快速构造自定义标量(仅生成场景适用)
不需要额外封装复杂逻辑,写个快捷方法构造带标签的标量节点,直接替换哈希里的字符串值就行:
require 'psych' # 构造CloudFormation自定义标签值 def cfn_tag(tag_name, value) Psych::Nodes::Scalar.new( value, nil, nil, false, false, Psych::Nodes::Scalar::PLAIN # 强制纯文本格式输出,不自动加引号 ).tap { |node| node.tag = "!#{tag_name}" } end template = { 'FooPolicy' => { 'Type' => 'AWS::SQS::QueuePolicy', 'Properties' => { 'Queues' => cfn_tag('Ref', 'FooQueue'), 'PolicyDocument' => { 'Statement' => { 'Action' => 'SQS:*', 'Effect' => 'Allow', 'Resource' => cfn_tag('GetAtt', 'FooQueue.Arn'), 'Principal' => { 'AWS' => '${AWS::AccountId}' } } } } } } # 序列化时关闭自动折行转义,去掉默认YAML文档头 output = Psych.dump( template, indentation: 2, line_width: -1 ).gsub(/^---\n/, '') puts output
运行后输出完全符合CloudFormation格式要求:
FooPolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: !Ref FooQueue PolicyDocument: Statement: Action: SQS:* Effect: Allow Resource: !GetAtt FooQueue.Arn Principal: AWS: ${AWS::AccountId}
方式2:注册自定义标签类(序列化/反序列化双向兼容)
如果场景需要同时支持解析现有CloudFormation模板、生成新模板,可以注册专属标签类,适配Psych的编解码钩子:
class CfnTag attr_accessor :tag, :value def initialize(tag, value) @tag = tag @value = value end # 序列化逻辑 def encode_with(coder) coder.tag = "!#{@tag}" coder.scalar = @value coder.style = Psych::Nodes::Scalar::PLAIN end # 反序列化逻辑 def init_with(coder) @tag = coder.tag.sub(/^!/, '') @value = coder.scalar end end # 注册常用CloudFormation标签 %w[Ref GetAtt Sub ImportValue Select Split].each do |tag| Psych.add_tag("!#{tag}", CfnTag) end
后续构造哈希时直接传入CfnTag.new('Ref', 'FooQueue')这类实例即可,双向转换都不会出现多余引号或标签识别错误。
注意事项
- 不要用正则全局替换输出结果里的双引号,会导致本身包含冒号、空格、换行等特殊字符、确实需要引号包裹的值出现格式错误。
- 遇到普通伪参数(比如
${AWS::Region}、${AWS::AccountId})被自动加引号的情况,给Psych.dump传入line_width: -1参数关闭自动折行和过度转义即可解决。
内容的提问来源于stack exchange,提问作者Bao Thai
相关产品推荐
相关产品推荐

