0

I'm trying to edit a yaml file but when I write the new file the whole structure of the file is messed up.

Line breaks are wrong, some indentations are wrong as well and it even deletes some of my parameters for some reason. Here's an example:

Before

AWSTemplateFormatVersion: "2010-09-09"
Metadata:
    Generator: "user"
Description: "CloudFormation blah blah"

Parameters:
  VPCEndpointServiceServiceName:
    Description: VPCEndpointServiceServiceName
    Type: String

Mappings:
  PrivateLink:
    EndPoint:
      EndPointName: test
      EndPointVpcId: vpc-123
      SecurityGroupIds: sg-123
      SubnetId1: subnet-123
      SubnetId2: subnet-123

Resources:
    EC2VPCEndpoint:
        Type: "AWS::EC2::VPCEndpoint"
        Properties:
            VpcEndpointType: "Interface"
            VpcId: !FindInMap [PrivateLink, EndPoint, EndPointVpcId]
            ServiceName: !Ref VPCEndpointServiceServiceName
            SubnetIds:
              - !FindInMap [PrivateLink, EndPoint, SubnetId1]
              - !FindInMap [PrivateLink, EndPoint, SubnetId2]
            PrivateDnsEnabled: false
            SecurityGroupIds:
              - !FindInMap [PrivateLink, EndPoint, SecurityGroupIds]

After

AWSTemplateFormatVersion: '2010-09-09'
Metadata:
  Generator: user
Description: CloudFormation blah blah
Parameters:
  VPCEndpointServiceServiceName:
    Description: VPCEndpointServiceServiceName
    Type: String
Mappings:
  PrivateLink:
    EndPoint:
      EndPointName: test
      EndPointVpcId: vpc-123
      SecurityGroupIds: sg-123
      SubnetId1: subnet-123
      SubnetId2: subnet-123
Resources:
  EC2VPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcEndpointType: Interface
      VpcId:
      - PrivateLink
      - EndPoint
      - EndPointVpcId
      ServiceName: VPCEndpointServiceServiceName
      SubnetIds:
      - - PrivateLink
        - EndPoint
        - SubnetId1
      - - PrivateLink
        - EndPoint
        - SubnetId2
      PrivateDnsEnabled: 'false'
      SecurityGroupIds:
      - - PrivateLink
        - EndPoint
        - SecurityGroupIds

What's really weird is that it also removes parameters like !FindInMap and !Ref.

Here's my function:

def editEndpointTemplate(endpoint_tempplate_path):
    #read yaml file
    with open(endpoint_tempplate_path) as file:
        data = yaml.load(file, Loader=yaml.BaseLoader)

    data['Mappings']['PrivateLink']['EndPoint']['EndPointName'] = "New Name"

    #write yaml file and overwrite old one.
    with open(endpoint_tempplate_path, 'w') as file:
        yaml.dump(data, file, sort_keys=False)

I want to preserve the file exactly as it is because all I do is update a few keys.

I also had issues with the file being sorted alphabetically, but a simple sort_keys=False fixed that. I figured any other of PyYaml's attributes would solve this but couldn't figure it out.

Any help would be appreciated.

Daniel
  • 621
  • 5
  • 22
  • may be this could be of help: https://stackoverflow.com/questions/50914422/parse-an-aws-cloudformation-template-with-the-pyyaml-library – Krishna Chaurasia Feb 17 '21 at 11:34
  • Does this answer your question? [I want to load a YAML file, possibly edit the data, and then dump it again. How can I preserve formatting?](https://stackoverflow.com/questions/60891174/i-want-to-load-a-yaml-file-possibly-edit-the-data-and-then-dump-it-again-how) – flyx Feb 17 '21 at 11:43
  • @KrishnaChaurasia Thank you. It's indeed the closest thing I found so far. The structure is still not the same though :( – Daniel Feb 17 '21 at 11:52

1 Answers1

0

Found a workaround. Instead of using PyYaml or cfn-tools, I used ruamel.yaml.

import sys
from ruamel.yaml import YAML

def editEndpointTemplate(endpoint_template_path):
    yaml = YAML()
    yaml.indent(mapping=3)

    #Load yaml file
    with open(endpoint_template_path) as fp:
        data = yaml.load(fp)

    #Change data
    data['Mappings']['PrivateLink']['EndPoint']['EndPointName'] = service_name

    #Dump it back to the same file
    # yaml.dump(data, sys.stdout)
    with open(endpoint_template_path, 'w') as fp:
        yaml.dump(data, fp)

The new YAML file is preserved exactly like my template, even after editing.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Daniel
  • 621
  • 5
  • 22