cfoo 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.simplecov +4 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +676 -0
- data/README.md +166 -0
- data/Rakefile +10 -0
- data/TODO +29 -0
- data/bin/cfoo +26 -0
- data/cfoo.gemspec +35 -0
- data/features/attribute_expansion.feature +43 -0
- data/features/convert_yaml_to_json.feature +69 -0
- data/features/el_escaping.feature +21 -0
- data/features/map_reference_expansion.feature +68 -0
- data/features/modules.feature +101 -0
- data/features/parse_files.feature +46 -0
- data/features/reference_expansion.feature +49 -0
- data/features/step_definitions/cfoo_steps.rb +107 -0
- data/features/support/env.rb +5 -0
- data/features/yamly_shortcuts.feature +132 -0
- data/lib/cfoo.rb +11 -0
- data/lib/cfoo/cfoo.rb +15 -0
- data/lib/cfoo/el_parser.rb +105 -0
- data/lib/cfoo/file_system.rb +28 -0
- data/lib/cfoo/module.rb +25 -0
- data/lib/cfoo/parser.rb +82 -0
- data/lib/cfoo/processor.rb +38 -0
- data/lib/cfoo/project.rb +16 -0
- data/lib/cfoo/renderer.rb +9 -0
- data/lib/cfoo/version.rb +3 -0
- data/lib/cfoo/yaml.rb +34 -0
- data/lib/cfoo/yaml_parser.rb +16 -0
- data/spec/cfoo/cfoo_spec.rb +31 -0
- data/spec/cfoo/el_parser_spec.rb +47 -0
- data/spec/cfoo/file_system_spec.rb +61 -0
- data/spec/cfoo/module_spec.rb +16 -0
- data/spec/cfoo/parser_spec.rb +148 -0
- data/spec/cfoo/processor_spec.rb +52 -0
- data/spec/cfoo/project_spec.rb +16 -0
- data/spec/cfoo/renderer_spec.rb +19 -0
- data/spec/cfoo/yaml_parser_spec.rb +79 -0
- data/spec/spec_helper.rb +2 -0
- metadata +235 -0
data/README.md
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
# Cfoo
|
2
|
+
|
3
|
+
[](https://travis-ci.org/drrb/cfoo)
|
4
|
+
[](https://coveralls.io/r/drrb/cfoo)
|
5
|
+
[](https://codeclimate.com/github/drrb/cfoo)
|
6
|
+
|
7
|
+
Write your CloudFormation templates in a YAML-based markup language
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Cfoo can be installed as a Ruby Gem
|
12
|
+
|
13
|
+
$ gem install cfoo
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Process some Cfoo templates from the command line
|
18
|
+
|
19
|
+
$ cfoo web-server-template.yml database_template.yml
|
20
|
+
|
21
|
+
## Templates
|
22
|
+
|
23
|
+
### Comparison with standard CloudFormation templates
|
24
|
+
|
25
|
+
Snippet from a CloudFormation template (based on [this example](https://s3.amazonaws.com/cloudformation-templates-us-east-1/Rails_Single_Instance.template)):
|
26
|
+
|
27
|
+
```json
|
28
|
+
"Properties": {
|
29
|
+
"ImageId" : { "Fn::FindInMap" : [ "AWSRegion2AMI", { "Ref" : "AWS::Region" }, "AMI" ] },
|
30
|
+
"InstanceType" : { "Ref" : "InstanceType" },
|
31
|
+
"SecurityGroups" : [ {"Ref" : "FrontendGroup"} ],
|
32
|
+
"KeyName" : { "Ref" : "KeyName" },
|
33
|
+
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
|
34
|
+
"#!/bin/bash -v\n",
|
35
|
+
"yum update -y aws-cfn-bootstrap\n",
|
36
|
+
|
37
|
+
"function error_exit\n",
|
38
|
+
"{\n",
|
39
|
+
" /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", { "Ref" : "WaitHandle" }, "'\n",
|
40
|
+
" exit 1\n",
|
41
|
+
"}\n",
|
42
|
+
|
43
|
+
"/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackId" }, " -r WebServer ",
|
44
|
+
" --region ", { "Ref" : "AWS::Region" }, " || error_exit 'Failed to run cfn-init'\n",
|
45
|
+
|
46
|
+
"/opt/aws/bin/cfn-signal -e 0 -r \"cfn-init complete\" '", { "Ref" : "WaitHandle" }, "'\n"
|
47
|
+
]]}}
|
48
|
+
}
|
49
|
+
```
|
50
|
+
|
51
|
+
Equivalent Cfoo template snippet:
|
52
|
+
|
53
|
+
```yaml
|
54
|
+
Properties:
|
55
|
+
ImageId : AWSRegion2AMI[$(AWS::Region)][AMI]
|
56
|
+
InstanceType: $(InstanceType)
|
57
|
+
SecurityGroups:
|
58
|
+
- $(FrontendGroup)
|
59
|
+
KeyName: $(KeyName)
|
60
|
+
UserData: !Base64 |
|
61
|
+
#!/bin/bash -v
|
62
|
+
yum update -y aws-cfn-bootstrap
|
63
|
+
|
64
|
+
function error_exit
|
65
|
+
{
|
66
|
+
/opt/aws/bin/cfn-signal -e 1 -r "$1" '$(WaitHandle)'
|
67
|
+
exit 1
|
68
|
+
}
|
69
|
+
|
70
|
+
/opt/aws/bin/cfn-init -s $(AWS::StackId) -r WebServer --region $(AWS::Region) || error_exit 'Failed to run cfn-init'
|
71
|
+
|
72
|
+
/opt/aws/bin/cfn-signal -e 0 -r "cfn-init completed" '$(WaitHandle)'
|
73
|
+
```
|
74
|
+
|
75
|
+
### Shortcuts
|
76
|
+
|
77
|
+
Cfoo allows you to simplify CloudFormation [intrinsic function](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html)
|
78
|
+
references using its own shorthand
|
79
|
+
|
80
|
+
##### Reference
|
81
|
+
|
82
|
+
CloudFormation: `{ "Ref" : "InstanceType" }`
|
83
|
+
|
84
|
+
Cfoo Shortcut: `$(InstanceType)`
|
85
|
+
|
86
|
+
##### Mapping Reference
|
87
|
+
|
88
|
+
CloudFormation: `{ "FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ] }`
|
89
|
+
|
90
|
+
Cfoo Shortcut: `$(SubnetConfig[VPC][CIDR])`
|
91
|
+
|
92
|
+
##### Attribute Reference
|
93
|
+
|
94
|
+
CloudFormation: `{ "Fn::GetAtt" : [ "Ec2Instance", "PublicIp" ] }`
|
95
|
+
|
96
|
+
Cfoo Shortcut: `$(Ec2Instance.PublicIp)`
|
97
|
+
|
98
|
+
Other Shortcut: `$(Ec2Instance[PublicIp])`
|
99
|
+
|
100
|
+
##### Embedded Reference
|
101
|
+
|
102
|
+
CloudFormation: `{ "Fn::Join" : [ "", [{"Ref" : "HostedZone"}, "." ]]}`
|
103
|
+
|
104
|
+
Cfoo Shortcut: `$(HostedZone).`
|
105
|
+
|
106
|
+
### YAML Types
|
107
|
+
|
108
|
+
Cfoo gives you the option of using YAML custom data-types where it helps to make your templates easier to read.
|
109
|
+
The table below uses inline YAML lists, but multiline lists can also be used.
|
110
|
+
|
111
|
+
##### Reference
|
112
|
+
|
113
|
+
CloudFormation: `{ "Ref" : "InstanceType" }`
|
114
|
+
|
115
|
+
YAML Type: `!Ref InstanceType`
|
116
|
+
|
117
|
+
##### Mapping Reference
|
118
|
+
|
119
|
+
CloudFormation: `{ "FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ] }`
|
120
|
+
|
121
|
+
YAML Type: `!FindInMap [ SubnetConfig, VPC, CIDR ]`
|
122
|
+
|
123
|
+
##### Attribute Reference
|
124
|
+
|
125
|
+
CloudFormation: `{ "Fn::GetAtt" : [ "Ec2Instance", "PublicIp" ] }`
|
126
|
+
|
127
|
+
YAML Type: `!GetAtt [ Ec2Instance, PublicIp ]`
|
128
|
+
|
129
|
+
##### Base64 String
|
130
|
+
|
131
|
+
CloudFormation: `{ "Fn::Base64" : "#!/bin/bash\necho 'Running script...'" }`
|
132
|
+
|
133
|
+
YAML Type: `!Base64 "#!/bin/bash\necho 'running script...'"`
|
134
|
+
|
135
|
+
## Goals
|
136
|
+
|
137
|
+
### Primary Goals
|
138
|
+
|
139
|
+
Cfoo aims to let developers simplify CloudFormation templates by:
|
140
|
+
|
141
|
+
- allowing them to write templates in YAML
|
142
|
+
- providing an expression language to simplify CF Ref/Attr/etc expressions
|
143
|
+
- allowing templates to be split up into logical components (to simplify and share)
|
144
|
+
|
145
|
+
### Secondary Goals
|
146
|
+
|
147
|
+
Cfoo aims (subject to Primary Goals) to:
|
148
|
+
|
149
|
+
- allow all aspects of CloudFormation templates to be expressed in YAML (so you don't need to use JSON)
|
150
|
+
- allow inclusion existing JSON templates (so you don't have to switch all at once)
|
151
|
+
|
152
|
+
### Non-goals
|
153
|
+
|
154
|
+
Cfoo does not (yet) aim to:
|
155
|
+
|
156
|
+
- provide commandline utilities for interacting directly with CloudFormation (it just generates the templates for now)
|
157
|
+
- resolve/validate references (the CloudFormation API already does this)
|
158
|
+
|
159
|
+
## Contributing
|
160
|
+
|
161
|
+
1. Fork it
|
162
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
163
|
+
3. Make your changes (with tests please)
|
164
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
165
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
166
|
+
6. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'cucumber/rake/task'
|
4
|
+
require 'coveralls/rake/task'
|
5
|
+
|
6
|
+
Coveralls::RakeTask.new
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
Cucumber::Rake::Task.new(:features)
|
9
|
+
|
10
|
+
task :default => [:spec, :features, 'coveralls:push']
|
data/TODO
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Features
|
2
|
+
----------
|
3
|
+
More tests for EL parsing
|
4
|
+
Spaces in EL?
|
5
|
+
More than [A-Za-z:] in EL identifiers?
|
6
|
+
Shorthand for AWS variables (e.g. { "Ref" : "AWS::StackId" } )
|
7
|
+
Shorthand for Fn::GetAZs
|
8
|
+
Better errors when parsing fails
|
9
|
+
Split into resources/mappings/parameters/etc by putting templates into directories with those names
|
10
|
+
Allow directory for raw templates
|
11
|
+
Allow traditional JSON CloudFormation templates (including modules, splitting, etc)
|
12
|
+
Vim highlighting
|
13
|
+
Use multi-json instead of json gem (spec.add_dependency 'multi_json', '~> 1.0')
|
14
|
+
Disablable warnings about naming conventions
|
15
|
+
Allow module references to remote templates (inc. Git repositories) (auto-included)
|
16
|
+
Allow rendering only part of the project (in case part of the infrastructure already exists)
|
17
|
+
Render templates with ERB to allow extra flexibility/substitution
|
18
|
+
Resolve EL and complain/fail if targets don't exist
|
19
|
+
Unit testing for templates
|
20
|
+
|
21
|
+
Tests
|
22
|
+
----------
|
23
|
+
|
24
|
+
Tasks
|
25
|
+
----------
|
26
|
+
Refactor EL parser
|
27
|
+
|
28
|
+
Bugs
|
29
|
+
----------
|
data/bin/cfoo
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib_path = File.expand_path('../../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include? lib_path
|
5
|
+
require 'cfoo'
|
6
|
+
|
7
|
+
if ARGV.include? "--help"
|
8
|
+
STDERR.puts "Usage: #{File.basename $0} [filename...]"
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
filenames = ARGV
|
13
|
+
|
14
|
+
yaml_parser = Cfoo::YamlParser.new
|
15
|
+
file_system = Cfoo::FileSystem.new(".", yaml_parser)
|
16
|
+
project = Cfoo::Project.new(file_system)
|
17
|
+
parser = Cfoo::Parser.new(file_system)
|
18
|
+
processor = Cfoo::Processor.new(parser, project)
|
19
|
+
renderer = Cfoo::Renderer.new
|
20
|
+
cfoo = Cfoo::Cfoo.new(processor, renderer, STDOUT)
|
21
|
+
|
22
|
+
if filenames.empty?
|
23
|
+
cfoo.build_project
|
24
|
+
else
|
25
|
+
cfoo.process *filenames
|
26
|
+
end
|
data/cfoo.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cfoo/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "cfoo"
|
8
|
+
gem.version = Cfoo::VERSION
|
9
|
+
gem.authors = ["drrb"]
|
10
|
+
gem.email = ["drrrrrrrrrrrb@gmail.com"]
|
11
|
+
gem.license = "GPL-3"
|
12
|
+
gem.description = "Cfoo: CloudFormation master"
|
13
|
+
gem.summary = <<-EOF
|
14
|
+
Cfoo (pronounced 'sifu') allows you to write your CloudFormation templates in a
|
15
|
+
YAML-based markup language, and organise it into modules to make it easier to
|
16
|
+
maintain.
|
17
|
+
EOF
|
18
|
+
gem.homepage = "https://github.com/drrb/cfoo"
|
19
|
+
|
20
|
+
gem.files = `git ls-files`.split($/)
|
21
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
22
|
+
gem.test_files = gem.files.grep(%r{^(spec|features)/})
|
23
|
+
gem.require_paths = ["lib"]
|
24
|
+
|
25
|
+
gem.add_dependency "json"
|
26
|
+
gem.add_dependency "parslet"
|
27
|
+
|
28
|
+
gem.add_development_dependency "bundler", "~> 1.3"
|
29
|
+
gem.add_development_dependency "rake"
|
30
|
+
gem.add_development_dependency "rspec"
|
31
|
+
gem.add_development_dependency "cucumber"
|
32
|
+
gem.add_development_dependency "simplecov"
|
33
|
+
gem.add_development_dependency "coveralls", ">= 0.6.3"
|
34
|
+
gem.add_development_dependency "json" # Coveralls needs it
|
35
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Feature: Expand EL Attribute References
|
2
|
+
As a CloudFormation user
|
3
|
+
I want to use an expression language as a shorthand for references
|
4
|
+
So that I my templates are easier to read
|
5
|
+
|
6
|
+
Scenario: Attribute expansion
|
7
|
+
Given I have a file "outputs.yml" containing
|
8
|
+
"""
|
9
|
+
EntryPoint:
|
10
|
+
Description: IP address of the Bastion Host
|
11
|
+
Value: $(BastionHost.PublicIp)
|
12
|
+
"""
|
13
|
+
When I process "outputs.yml"
|
14
|
+
Then the output should match JSON
|
15
|
+
"""
|
16
|
+
{
|
17
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
18
|
+
"EntryPoint" : {
|
19
|
+
"Description" : "IP address of the Bastion Host",
|
20
|
+
"Value" : { "Fn::GetAtt" : [ "BastionHost", "PublicIp" ]}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
"""
|
24
|
+
|
25
|
+
Scenario: Embedded attribute expansion
|
26
|
+
Given I have a file "outputs.yml" containing
|
27
|
+
"""
|
28
|
+
WebSite:
|
29
|
+
Description: URL of the website
|
30
|
+
Value: http://$(PublicElasticLoadBalancer.DNSName)/index.html
|
31
|
+
"""
|
32
|
+
When I process "outputs.yml"
|
33
|
+
Then the output should match JSON
|
34
|
+
"""
|
35
|
+
{
|
36
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
37
|
+
"WebSite" : {
|
38
|
+
"Description" : "URL of the website",
|
39
|
+
"Value" : { "Fn::Join" : [ "", [ "http://", { "Fn::GetAtt" : [ "PublicElasticLoadBalancer", "DNSName" ]}, "/index.html"]]}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
"""
|
43
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
Feature: Convert YAML to JSON
|
2
|
+
As a JSON provider
|
3
|
+
I want to generate my JSON from YAML
|
4
|
+
So that it's easier to read
|
5
|
+
|
6
|
+
Scenario: Basic array conversion
|
7
|
+
Given I have a file "list.yml" containing
|
8
|
+
"""
|
9
|
+
list:
|
10
|
+
- One
|
11
|
+
- 2
|
12
|
+
- "3"
|
13
|
+
"""
|
14
|
+
When I process "list.yml"
|
15
|
+
Then the output should match JSON
|
16
|
+
"""
|
17
|
+
{
|
18
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
19
|
+
"list" : ["One", 2, "3"]
|
20
|
+
}
|
21
|
+
"""
|
22
|
+
|
23
|
+
Scenario: Basic map conversion
|
24
|
+
Given I have a file "map.yml" containing
|
25
|
+
"""
|
26
|
+
1: One
|
27
|
+
2: Two
|
28
|
+
3: Three
|
29
|
+
"""
|
30
|
+
When I process "map.yml"
|
31
|
+
Then the output should match JSON
|
32
|
+
"""
|
33
|
+
{
|
34
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
35
|
+
"1" : "One",
|
36
|
+
"2" : "Two",
|
37
|
+
"3" : "Three"
|
38
|
+
}
|
39
|
+
"""
|
40
|
+
|
41
|
+
Scenario: Embedded map structure
|
42
|
+
Given I have a file "embeddedmap.yml" containing
|
43
|
+
"""
|
44
|
+
Fruit:
|
45
|
+
- Apples: [ red, green ]
|
46
|
+
- Bananas
|
47
|
+
- Grapes: [ seeded, seedless ]
|
48
|
+
Vegetables:
|
49
|
+
- Beans: [ red, black ]
|
50
|
+
- Sweet Corn
|
51
|
+
- Mirleton
|
52
|
+
"""
|
53
|
+
When I process "embeddedmap.yml"
|
54
|
+
Then the output should match JSON
|
55
|
+
"""
|
56
|
+
{
|
57
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
58
|
+
"Fruit": [
|
59
|
+
{ "Apples": [ "red", "green" ] },
|
60
|
+
"Bananas",
|
61
|
+
{ "Grapes": [ "seeded", "seedless" ] }
|
62
|
+
],
|
63
|
+
"Vegetables": [
|
64
|
+
{ "Beans": [ "red", "black" ] },
|
65
|
+
"Sweet Corn",
|
66
|
+
"Mirleton"
|
67
|
+
]
|
68
|
+
}
|
69
|
+
"""
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Feature: EL escaping
|
2
|
+
As a CloudFormation user
|
3
|
+
I want to to be able to escape the EL
|
4
|
+
So that I can type whatever text I want
|
5
|
+
|
6
|
+
Scenario: Escape EL
|
7
|
+
Given I have a file "outputs.yml" containing
|
8
|
+
"""
|
9
|
+
EntryPoint:
|
10
|
+
Value: \$(BastionHost.PublicIp)
|
11
|
+
"""
|
12
|
+
When I process "outputs.yml"
|
13
|
+
Then the output should match JSON
|
14
|
+
"""
|
15
|
+
{
|
16
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
17
|
+
"EntryPoint" : {
|
18
|
+
"Value" : "$(BastionHost.PublicIp)"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
"""
|
@@ -0,0 +1,68 @@
|
|
1
|
+
Feature: Expand EL Mapping References
|
2
|
+
As a CloudFormation user
|
3
|
+
I want to use an expression language as a shorthand for mapping references
|
4
|
+
So that I my templates are easier to read
|
5
|
+
|
6
|
+
Scenario: Map reference expansion
|
7
|
+
Given I have a file "outputs.yml" containing
|
8
|
+
"""
|
9
|
+
EntryPoint:
|
10
|
+
Description: IP address of the Bastion Host
|
11
|
+
Value: $(SubnetConfig[VPC][CIDR])
|
12
|
+
"""
|
13
|
+
When I process "outputs.yml"
|
14
|
+
Then the output should match JSON
|
15
|
+
"""
|
16
|
+
{
|
17
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
18
|
+
"EntryPoint" : {
|
19
|
+
"Description" : "IP address of the Bastion Host",
|
20
|
+
"Value" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
"""
|
24
|
+
|
25
|
+
Scenario: Embedded map reference expansion
|
26
|
+
Given I have a file "outputs.yml" containing
|
27
|
+
"""
|
28
|
+
WebSite:
|
29
|
+
Description: URL of the website
|
30
|
+
Value: http://$(Network[Dns][LoadBalancerDnsName])/index.html
|
31
|
+
"""
|
32
|
+
When I process "outputs.yml"
|
33
|
+
Then the output should match JSON
|
34
|
+
"""
|
35
|
+
{
|
36
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
37
|
+
"WebSite" : {
|
38
|
+
"Description" : "URL of the website",
|
39
|
+
"Value" : { "Fn::Join" : [ "", [ "http://", { "Fn::FindInMap" : [ "Network", "Dns", "LoadBalancerDnsName" ]}, "/index.html"]]}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
"""
|
43
|
+
|
44
|
+
Scenario: Map key is reference
|
45
|
+
Given I have a file "nat.yml" containing
|
46
|
+
"""
|
47
|
+
Resources:
|
48
|
+
NATDevice:
|
49
|
+
Type: AWS::EC2::Instance
|
50
|
+
Properties:
|
51
|
+
ImageId: $(AWSNATAMI[$(AWS::Region)][AMI])
|
52
|
+
"""
|
53
|
+
When I process "nat.yml"
|
54
|
+
Then the output should match JSON
|
55
|
+
"""
|
56
|
+
{
|
57
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
58
|
+
"Resources" : {
|
59
|
+
"NATDevice" : {
|
60
|
+
"Type" : "AWS::EC2::Instance",
|
61
|
+
"Properties" : {
|
62
|
+
"ImageId" : { "Fn::FindInMap" : [ "AWSNATAMI" , { "Ref" : "AWS::Region" } , "AMI" ] }
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
"""
|
68
|
+
|