Skip to content

Failure to load and dump template which has FindInMap inside GetAtt #120

Open
@pnickerson-cashstar

Description

@pnickerson-cashstar

Here is a valid CloudFormation template, which can be used to successfully create a stack, and the resources and tag show up as expected:

AWSTemplateFormatVersion: "2010-09-09"

Mappings:
  S3Domains:
    Bucket1:
      DomainResource: S3Bucket1
      DomainAttribute: DomainName

Transform: AWS::LanguageExtensions

Resources:
  S3Bucket1:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-one

  S3Bucket2:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-two
      Tags:
        - Key: Bucket1Domain
          Value:
            Fn::GetAtt:
              - Fn::FindInMap:
                - S3Domains
                - Bucket1
                - DomainResource
              - Fn::FindInMap:
                - S3Domains
                - Bucket1
                - DomainAttribute

AWS documentation says that FindInMap can be used inside of GetAtt here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html#getatt-supported-functions

However, when I try to parse this template in a Python 3.13.3 script using cfn-flip 1.3.0, I get an error:

import cfn_flip
file = open("template1.yaml", "r")
file_content = file.read()
loaded_yaml = cfn_flip.load_yaml(file_content)
cfn_flip.dump_yaml(loaded_yaml)
Traceback (most recent call last):
  File "<python-input-5>", line 1, in <module>
    cfn_flip.dump_yaml(loaded_yaml)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/__init__.py", line 42, in dump_yaml
    return yaml.dump(
           ~~~~~~~~~^
        data,
        ^^^^^
    ...<3 lines>...
        width=config.max_col_width
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib64/python3.13/site-packages/yaml/__init__.py", line 253, in dump
    return dump_all([data], stream, Dumper=Dumper, **kwds)
  File "/usr/lib64/python3.13/site-packages/yaml/__init__.py", line 241, in dump_all
    dumper.represent(data)
    ~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 27, in represent
    node = self.represent_data(data)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 199, in represent_list
    return self.represent_sequence('tag:yaml.org,2002:seq', data)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 92, in represent_sequence
    node_item = self.represent_data(item)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 105, in map_representer
    return fn_representer(dumper, key[4:], value[key])
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 80, in fn_representer
    value = ".".join(value)
TypeError: sequence item 0: expected str instance, ODict found

If I alter the template to no longer have FindInMap in GetAtt, I can run the Python fine.

AWSTemplateFormatVersion: "2010-09-09"

Mappings:
  S3Domains:
    Bucket1:
      DomainResource: S3Bucket1
      DomainAttribute: DomainName

Transform: AWS::LanguageExtensions

Resources:
  S3Bucket1:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-one

  S3Bucket2:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-two
      Tags:
        - Key: Bucket1Domain
          Value:
            Fn::GetAtt:
              - S3Bucket1
              - DomainName
"AWSTemplateFormatVersion: '2010-09-09'\nMappings:\n  S3Domains:\n    Bucket1:\n      DomainResource: S3Bucket1\n      DomainAttribute: DomainName\nTransform: AWS::LanguageExtensions\nResources:\n  S3Bucket1:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: my-bucket-one\n  S3Bucket2:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: my-bucket-two\n      Tags:\n        - Key: Bucket1Domain\n          Value: !GetAtt 'S3Bucket1.DomainName'\n"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions