Browse Source

Rewrite README to explain functionality, move forward TODO list

master
Adam Pippin 3 years ago
parent
commit
f71b5f3582
  1. 207
      README.md

207
README.md

@ -2,29 +2,218 @@
## Goal
Make it easier to re-use and template CloudFormation templates
Make it easier to write, re-use and template CloudFormation templates
## Functionality
## What it does
### Current
* Works with existing CloudFormation templates. (Some possible issues with the Symfony YAML parser notwithstanding.)
* Adds support for a `cfnpp:` meta block which provides some extended functionality detailed below.
* Adds several additional `!function`s detailed below.
* More planned, detailed at the end of the README.
* Supports serializing/deserializing yaml
* Can specify an input file; will pull in all referencing files and merge them and write to an output file
* Supports `!Unset` and `!Replace`
### Meta Block
### Planned
At the top level, a `cfnpp` block can be specified to make use of some extended functionality:
* Provision rendered templates directly to CloudFormation
* Includes
* Variables
For example:
```yaml
cfnpp:
stack:
- parent.yaml
variables:
A: 1
B: 2
foo: bar
```
#### Stack
Any files listed will be processed in the order given _before_ the current document. If those documents specify
any documents in their stack, those will be processed before those documents in the order given and so on.
There is nothing preventing you from including a file more than once, nor from creating a loop. It's undecided at
the time being whether this is desirable or whether we need some more complicated dependency graph or something to
process these.
The first document is loaded, then each subsequent document is merged with it, and then any functions present processed.
Merging follows some simple rules:
* Maps are merged, with duplicate keys being overwritten.
* Arrays are appended.
* Scalars overwrite.
* Any type mismatch, and the value in the template being merged in simply overwrites whatever's in the original.
For example, starting with:
```yaml
Resources:
Resource1:
Name: My Resource Name
VpcId: vpc-1234
AvailabilityZones:
- us-east-1a
- us-east-1b
ValidUsers:
Alice: 'aws:arn:1234:alice'
Bob: 'aws:arn:1234:bob'
AllowPorts:
- 80
- 443
```
And merging in:
```yaml
Resources:
Resource1:
Name: New Name
AvailabilityZones:
- us-east-1c
ValidUsers:
Charlie: 'aws:arn:1234:charlie'
AllowPorts: False
```
Will result in:
```yaml
Resources:
Resource1:
Name: New Name
VpcId: vpc-1234
AvailabilityZones:
- us-east-1a
- us-east-1b
- us-east-1c
ValidUsers:
Alice: 'aws:arn:1234:alice'
Bob: 'aws:arn:1234:bob'
Charlie: 'aws:arn:1234:charlie'
AllowPorts: False
```
#### Variables
Variables listed are set from all templates before the first one is processed. Variables are processed in the same
order that the documents will be compiled, and later values will overwrite earlier ones.
That is, a base template can define some default values, and a dependent one can specify new values and they will
be visible to the base template.
### Functions
#### !replace
Tells the merging process to _not_ attempt to perform any merging, but simply replace whatever's in the target document
with these values. For example, given a base template:
```yaml
Resources;
Resource1:
AvailabilityZones:
- us-east-1a
- us-east-1b
- us-east-1c
```
Merging in:
```yaml
Resources:
Resource1:
AvailabilityZones: !Replace
- us-east-1c
```
Will result in:
```yaml
Resources:
Resource1:
AvailabilityZones:
- us-east-1c
```
#### !unset
Removes a property completely, rather than simply overriding its value or something.
The YAML parser requires that tags have a value, so simply pass '~' (null) or some
other garbage.
Given a base template:
```yaml
Resources:
Resource1:
Name: Test
SuperSecurityLevel: 5
```
Merging in:
```yaml
Resources:
Resource1:
SuperSecurityLevel: !unset ~
```
Will result in:
```yaml
Resources:
Resource1:
Name: Test
```
#### !var
Replaced with the (scalar) value of a variable.
Given:
```yaml
cfnpp:
variables:
A: 1
MyFavouriteNumber: !var A
```
Will result in:
```yaml
MyFavouriteNumber: 1
```
## Usage
### Running
* Install dependencies with `composer install`
* Execute `cfnpp` with PHP.
* Execute `cfnpp` with PHP 8, it will either complain about any missing PHP extensions or present a list of commands.
* Run `./cfnpp <infile.yaml> <outfile.yaml>`
### Building
Note: Building is not required to run.
* Install dependencies with `composer install`
* Run `./cfnpp app:build`; outputs phar at builds/
## TODO
* Provision rendered templates directly to CloudFormation
* Maybe look at implementing an actual dependency graph to make stuff like "multiple inheritance" a little cleaner.
E.g., if a single app stack pulls in multiple resources which all depend on `base.yaml`, don't reprocess base.yaml a
bunch of times but instead just realize that's the root and process it once.
* Add flow control: `!if`, `!foreach`, etc
* Extend variables to support arrays/maps. Probably write a helper or add a toArray on Node since we're having to
convert to/from dom nodes and arrays/maps all over the place.
* Build an expression parser. Just to make everyone's life difficult, because it's fun and this is a toy project, and
also to avoid having to care about operator precedence let's do it all postfix? My HP50G would be proud.
* Some sort of macro system would be good.

Loading…
Cancel
Save