-
Notifications
You must be signed in to change notification settings - Fork 197
Handling of AWS CloudFormation intrinsic functions in 0.1.0 #3
Comments
+1. Simpler than our initial approach to intrinsics, removing all type assertions. I agree with doing it iteratively, starting by not supporting them and resolve to a predefined value. Also agreed to parse YAML to JSON before goformation handles the code. I like this approach Paul. Would we consider the tag parsing feature in YAML's parser as a requirement for this, or can we iterate and release in parallel? |
+1 agreed with proposal. Two questions:
Goformation's main method must take a intrinsic parser object class as input. Today there is only one parser. If needed customers can extend this with new parsers that does more magic like resolve references to parameters etc. |
The YAML parser only would have a callback for inline intrinsics - i.e. YAML tags, like |
Okay. Why to JSON is my question. Why can't you unmarshall to a generic map for recursion? Why YAML -> JSON -> map when you can Yaml -> map? |
Good point. The input and output for the intrinsic processor can both just be interface{}. |
Actually, that doesn't help much. After intrinsic processing, the next step will be to unmarshal the processed output into Go structs. Rather than do that ourselves, it's easier to use the JSON unmarshaller. Hence why []byte of JSON made more sense as an output. |
The full flows would be YAML->map->JSON->(parsed template) for YAML templates, and JSON->(parsed template) for JSON templates, right? |
Okay so here is the flow for both: YAML -> handle !Ref style tags -> convert intrinsic objects to primitive types -> marshall to JSON -> unmarshall to Go Structs JSON -> map -> convert intrinsic objects to primitive types -> marshall to JSON -> unmarshall to Go Structs Is my understanding correct? I will take up with work to patch YAML parser to handle !Ref style tags. One of you can begin converting intrinsics to primitive types. Both look independent. Let's have Unit tests, unit tests, and unit tests! |
Yes, that's the correct flow. And just to be clear, "handle !Ref style tags" means convert them from short form (tag), into long form? i.e.
I'll work on a PR for the above proposal. |
Yes, you're right. Convert short form to long form. At which point it becomes just another object. I'll link it here once I have a PR out |
* Add SAM HTTP API WIP * Generate HTTP API code * Avoid stutters in property type names
Problem Statement
We need to be able to unmarshal AWS CloudFormation resources to typed Go structs, for example:
This is complicated, as within a CloudFormation template, a property (such as
Runtime
) could be a string, or it could be an AWS CloudFormation intrinsic function, such as:The above example would fail to unmarshal into the AWSLambdaFunction struct above with json.Unmarshal() or yaml.Unmarshal().
Considerations
!Sub
), which isn't supported in the Go YAML parser today (they get replaced with blank strings).Implementation
I propose we:
Submit a patch to the Go YAML parser to support tags, and provide a callback where the parser user choose what to replace for each tag.
We unmarhal all YAML templates into interface{}, then into JSON for handling within Goformation. This allows us to just focus on supporting a single template language in Goformation code.
I propose we implement a decoupled intrinsics handling package with a very simple interface that takes a JSON AWS CloudFormation template (as a []byte), processes all intrinsics, and returns the resulting JSON template (as a []byte).
This package will have a very simple API. Here is a usage example:
The resulting output of the above example would be:
Below is an implementation of the intrinsic handling package I am proposing.
It's pretty simple, and recurses through a JSON structure (
interface{}
), looking for intrinsic functions. If it finds any, it calls out to a hook function that does whatever it needs to in order to "resolve" the intrinsic function back from an object, into a simple primitive.This hook approach would allow us the possibility of resolving some intrinsic functions in the future if we wanted to, however in the initial implementation we would simply refuse to resolve any of the intrinsic functions, and just return a string value such as
"unsupported intrinsic function: Fn::Join"
.Reference Information
Possible intrinsic function formats (JSON):
List of intrinsic functions:
Fn::Base64
Fn::And
Fn::Equals
Fn::If
Fn::Not
Fn::Or
Fn::FindInMap
Fn::GetAtt
Fn::GetAZs
Fn::ImportValue
Fn::Join
Fn::Select
Fn::Split
Fn::Sub
Ref
The text was updated successfully, but these errors were encountered: