bazaarvoice / cloudformation-ruby-dsl

Ruby DSL for creating Cloudformation templates
Apache License 2.0
210 stars 76 forks source link

Added --output-yaml feature to the 'expand' action #123

Open ngtjah opened 6 years ago

ngtjah commented 6 years ago

Description

Since CloudFormation supports YAML I thought it would be nice to have the option to generate my templates in YAML. This is the first gem I've done a PR for, hopefully I did ok. The implementation is pretty bare-bones and has only been applied to the 'expand' action.

Steps to Test or Reproduce

./my-template.rb expand --output-yaml

Testing

I tested it with a pretty complex template, but I have not tested extensively.

jonaf commented 6 years ago

Hi, thanks for your pull request!

Before I review in detail, I was wondering if you could describe what this brings to the table over something like ./my-template.rb expand | ruby -ryaml -rjson -e 'puts YAML.dump(JSON.parse(STDIN.read))' ?

ngtjah commented 6 years ago

Sure jonaf, I use this project extensively and I enjoy using it. What you described should be equivalent to the what I added. The feature simply changes the key's symbols to strings and outputs with to_yaml. If this is not something that is desirable or if there is a better way to implement it I understand.

jonaf commented 6 years ago

I can see it being convenient if the community agrees. We should try to get community input before deciding.

In general, when dealing with the Ruby DSL, I try to forget whether I'm dealing with JSON or YAML. However, I'm not completely sure that converting directly from JSON to YAML will actually produce a valid template. Consider Cloudformation intrinsic functions, for example. Even knowing that YAML is a superset of JSON and that the long-form notation is somewhat compatible, I'm not sure that Cloudformation will accept YAML that looks like:

Property:
  Fn::Join:
    - delimiter
        - value1
        - value2

Since it expects (even in YAML) the format to be:

Property: Fn::Join: [ delimiter, [ comma-delimited list of values ] ]

While the latter is valid YAML (to my knowledge), I don't think that to_yaml will serialize it that way.

It certainly won't serialize to the short-form notation: !Join [ delimiter, [ comma-delimited list of values ] ].

ngtjah commented 6 years ago

Ya that sounds good as far as the community input.

I was looking further for the specifications from AWS, but this is about as much info as I could get from the documentation.

AWS CloudFormation Template Formats

YAML - AWS CloudFormation supports the YAML Version 1.1 specification with a few exceptions. AWS CloudFormation doesn't support the following features:

It would be interesting to look into the short-form notation which is supported in YAML 1.1, but to_yaml is rendering the long-form notation. Here is a piece of my testing output which CloudFormation did accept:

LookupStackOutputsCustom:
    Type: Custom::LookupStackOutputsLambda
    Properties:
      ServiceToken:
        Fn::Join:
        - ''
        - - 'arn:aws:lambda:'
          - us-west-2
          - ":"
          - Ref: AWS::AccountId
          - ":function:"
          - Ref: LookupStackOutputsLambdaFunc
      StackName:
        Fn::Join:
        - "-"
        - - Ref: CfnSegmentName
          - base
          - Ref: Environment

Also, my testing shows the rendered JSON template of 215K was reduced to 137K in size when rendered in YAML.

jonaf commented 6 years ago

That's very interesting! If a straight conversion to YAML does work, then I have no argument against implementing this naively. I'm impressed by the reduction in size (~36% smaller). Was this comparing the --nopretty JSON to YAML?

ngtjah commented 6 years ago

Great, I'm glad you are interested!

That was the pretty JSON, nopretty JSON still wins.

119K - NoPretty JSON (-45%) 137K - YAML (-36%) 215K - Pretty JSON