cfndsl 0.1.16 → 0.1.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3639153a22d283db62bc8c36f03ae111675e6482
4
- data.tar.gz: 8295dfbcbdc172a276a6b192ed99b5cc1d7769b3
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MzU3YmUxZDJhYTg1YWNjNmE5MWE5OWY3NDBiNzM5NjNhMTMxYmM4Mw==
5
+ data.tar.gz: !binary |-
6
+ OGM0MGQ3ZjY4YzllMDFiMGM2N2ZjNWNhZDhkN2U2OTVjY2QwYjhjMQ==
5
7
  SHA512:
6
- metadata.gz: 89870880a076338d49b2b5d05770206cb7ef30b3f179098331f9424b883b4e61ae6c2e33bc240808b91c4a441429429d332ddb3533db460c67f4becbd20ea866
7
- data.tar.gz: ce0e651c1738128b3513ac6da3badcf184795a21410952434685d71f83a3bebd64eabc579377c82d46467dd4ca80cd5cc442af21a31012bb058ecf82141e17f2
8
+ metadata.gz: !binary |-
9
+ ZmUwNTYyZmY0NjM4YWJmYzdhZmY2ZmVjNThmOTZhZTc0OGZjZDRmZmZjMzE5
10
+ N2UyNzg2NmM0MTJjZGUzMDNmMTc4YTk0ZmYxMjViMWY5MGQ0ZTI4ZDIzZmU2
11
+ MGNiZWU5Y2QxNWJlZmEyMTY3ZjMzNGQxYzBlYWFmOWNjNDlmMjE=
12
+ data.tar.gz: !binary |-
13
+ ZTczZDA1NTAzNDUyNDIwNGYxY2M4YjcxMjI3OWE1Mzc5YzQwNTM2MGQ3MjNi
14
+ ZWZiMWM0Y2ZhMWRkMGI4NGU2MDE5NDUyNDU0YjljYTQyNWNhY2JlNjU5Y2Qy
15
+ MDM1OWRkMTBlMTUxZDFiNzQ2NjU1NDQxNDYxMWNmNWQ2YmM4MjE=
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ *~
3
+ Gemfile.lock
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ sudo: false
5
+
6
+ deploy:
7
+ provider: rubygems
8
+ api_key:
9
+ secure: AH+4R+m6U0kmALFYAYEQl2oF/dj1yOnu/M1ZOtWttk+Zjwnw6kFc0hFLbvxdy6uivq1XmMXVa9eXzDPsRjW4ow2g+UuDLxvkvfT45SMmJ5sYQpoiD7AIJnEvMu6TXnmfiRNgM5bHnV3oilNJ8KKCbCFCd+imGRLTkBuhLkhkejA=
10
+ gem: cfndsl
11
+ on:
12
+ tags: true
13
+ repo: stevenjack/cfndsl
14
+ notifications:
15
+ email:
16
+ recipients:
17
+ - stevenmajack@gmail.com
18
+ on_failure: change
19
+ on_success: never
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rake'
7
+ gem 'rspec'
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Steven Jack
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,221 @@
1
+ cfndsl
2
+ ======
3
+
4
+ [![Build Status](https://travis-ci.org/stevenjack/cfndsl.png?branch=master)](https://travis-ci.org/stevenjack/cfndsl)
5
+ [![Gem Version](https://badge.fury.io/rb/cfndsl.png)](http://badge.fury.io/rb/cfndsl)
6
+ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/stevenjack/cfndsl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
7
+
8
+ [AWS Cloudformation](http://docs.amazonwebservices.com/AWSCloudFormation/latest/UserGuide/GettingStarted.html) templates are an incredibly powerful way to build
9
+ sets of resources in Amazon's AWS environment. Unfortunately, because
10
+ they are specified in JSON, they are also difficult to write and
11
+ maintain:
12
+
13
+ * JSON does not allow comments
14
+
15
+ * All structures are JSON, so it is sometimes easy for a person
16
+ reading a template to get lost.
17
+
18
+ * References and internal functions have a particularly unpleasant syntax.
19
+
20
+
21
+ The cnfdsl gem provides a simple DSL that allows you to write equivalent
22
+ templates in a more friendly language and generate the correct json
23
+ templates by running ruby.
24
+
25
+ ## Getting Started
26
+
27
+ sudo gem install cfndsl
28
+
29
+ Now write a template in the dsl
30
+
31
+ ```ruby
32
+
33
+ CloudFormation {
34
+ Description "Test"
35
+
36
+ Parameter("One") {
37
+ String
38
+ Default "Test"
39
+ MaxLength 15
40
+ }
41
+
42
+ Output(:One,FnBase64( Ref("One")))
43
+
44
+ EC2_Instance(:MyInstance) {
45
+ ImageId "ami-12345678"
46
+ }
47
+
48
+ }
49
+ ```
50
+
51
+ Then run cfndsl on the file
52
+
53
+ ```
54
+ chris@raspberrypi:~/git/cfndsl$ cfndsl test.rb | json_pp
55
+ {
56
+ "Parameters" : {
57
+ "One" : {
58
+ "Type" : "String",
59
+ "Default" : "Test",
60
+ "MaxLength" : 15
61
+ }
62
+ },
63
+ "Resources" : {
64
+ "MyInstance" : {
65
+ "Type" : "AWS::EC2::Instance",
66
+ "Properties" : {
67
+ "ImageId" : "ami-12345678"
68
+ }
69
+ }
70
+ },
71
+ "AWSTemplateFormatVersion" : "2010-09-09",
72
+ "Outputs" : {
73
+ "One" : {
74
+ "Value" : {
75
+ "Fn::Base64" : {
76
+ "Ref" : "One"
77
+ }
78
+ }
79
+ }
80
+ },
81
+ "Description" : "Test"
82
+ }
83
+ ```
84
+
85
+ *Aside: that is correct - a significant amount of the development for
86
+ this gem was done on a [Raspberry Pi](http://www.raspberrypi.org).*
87
+
88
+ ## Samples
89
+
90
+ There is a more detailed example in the samples directory. The file
91
+ "autoscale.template" is one of the standard Amazon sample templates.
92
+ "autoscale.rb" generates an equivalent template file.
93
+
94
+ ## Command Line Options
95
+
96
+ The cfndsl command line program now accepts some command line options.
97
+
98
+ ```
99
+ Usage: cfndsl [options] FILE
100
+ -o, --output FILE Write output to file
101
+ -y, --yaml FILE Import yaml file as local variables
102
+ -r, --ruby FILE Evaluate ruby file before template
103
+ -j, --json FILE Import json file as local variables
104
+ -D, --define "VARIABLE=VALUE" Directly set local VARIABLE as VALUE
105
+ -v, --verbose Turn on verbose ouptut
106
+ -h, --help Display this screen
107
+ ```
108
+
109
+ By default, cfndsl will attempt to evaluate FILE as cfndsl template and print
110
+ the resulting cloudformation json template to stdout. With the -o option, you
111
+ can instead have it write the resulting json template to a given file. The -v
112
+ option prints out additional information (to stderr) about what is happening
113
+ in the model generation process.
114
+
115
+ The -y, -j, -r and -D options can be used to control some things about the
116
+ environment that the template code gets evaluate in. For instance, the -D
117
+ option allows you to set a variable at the command line that can then be
118
+ referred to within the template itself.
119
+
120
+ This is best illustrated with a example. Consider the following cfndsl
121
+ template
122
+
123
+ ```ruby
124
+ # cfndsl template t1.rb
125
+ CloudFormation {
126
+
127
+ DESCRIPTION ||= "default description"
128
+ MACHINES ||= 3
129
+
130
+ Description DESCRIPTION
131
+
132
+ (1..MACHINES).each do |i|
133
+ name = "machine#{i}"
134
+ EC2_Instance(name) {
135
+ ImageId "ami-12345678"
136
+ Type "t1.micro"
137
+ }
138
+ end
139
+
140
+ }
141
+ ```
142
+
143
+ Note the two variables "DESCRIPTION" and "MACHINES". The template
144
+ sets these to some reasonable default values, and if you run cfndsl
145
+ on it without changing them in any way you get the following cloudformation
146
+ template:
147
+
148
+ ```json
149
+ {
150
+ "Resources": {
151
+ "machine1": {
152
+ "Type": "AWS::EC2::Instance",
153
+ "Properties": {
154
+ "ImageId": "ami-12345678"
155
+ }
156
+ }
157
+ },
158
+ "Description": "default description",
159
+ "AWSTemplateFormatVersion": "2010-09-09"
160
+ }
161
+ ```
162
+
163
+ However if you run the command
164
+
165
+ ```bash
166
+ $ cfndsl t1.rb -D 'DESCRIPTION="3 machine cluster"' -D 'MACHINES=3'
167
+ ```
168
+
169
+ you get the following generated template.
170
+
171
+ ```json
172
+ {
173
+ "Resources": {
174
+ "machine3": {
175
+ "Type": "AWS::EC2::Instance",
176
+ "Properties": {
177
+ "ImageId": "ami-12345678"
178
+ }
179
+ },
180
+ "machine2": {
181
+ "Type": "AWS::EC2::Instance",
182
+ "Properties": {
183
+ "ImageId": "ami-12345678"
184
+ }
185
+ },
186
+ "machine1": {
187
+ "Type": "AWS::EC2::Instance",
188
+ "Properties": {
189
+ "ImageId": "ami-12345678"
190
+ }
191
+ }
192
+ },
193
+ "Description": "3 machine cluster",
194
+ "AWSTemplateFormatVersion": "2010-09-09"
195
+ }
196
+ ```
197
+
198
+ The -y and -j options allow you to group several variable definitions
199
+ into a single file (formated as either yaml or ruby respectively). If
200
+ you had a file called 't1.yaml' that contained the following,
201
+
202
+ ```yaml
203
+ # t1.yaml
204
+ DESCRIPTION: 5 machine cluster
205
+ MACHINES: 5
206
+ ```
207
+
208
+ the command
209
+
210
+ ```bash
211
+ $ cfndsl t1.rb -y t1.yaml
212
+ ```
213
+
214
+ would generate a template with 5 instances declared.
215
+
216
+ Finally, the -r option gives you the opportunity to execute some
217
+ arbitrary ruby code in the evaluation context before the cloudformation
218
+ template is evaluated.
219
+
220
+
221
+
@@ -0,0 +1,55 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "cfndsl/version"
4
+
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task default: [:spec]
8
+
9
+ task :bump, :type do |t, args|
10
+ type = args[:type].downcase
11
+ version_path = "lib/cfndsl/version.rb"
12
+
13
+ fail unless %w(major minor patch).include? type
14
+
15
+ if `git rev-parse --abbrev-ref HEAD` != "master"
16
+ fail "Looks like you're trying to create a release in a branch, you can only create one in 'master'"
17
+ end
18
+
19
+ version_segments = CfnDsl::VERSION.split(".").map(&:to_i)
20
+
21
+ case type
22
+ when "major"
23
+ version_segments[0]+= 1
24
+ version_segments[1] = 0
25
+ version_segments[2] = 0
26
+ when "minor"
27
+ version_segments[1]+= 1
28
+ version_segments[2] = 0
29
+ when "patch"
30
+ version_segments[2]+= 1
31
+ end
32
+
33
+ version = version_segments.join(".")
34
+
35
+ puts "Bumping gem from version #{CfnDsl::VERSION} to #{version} as a '#{type.capitalize}' release"
36
+
37
+ contents = File.read version_path
38
+ updated_contents = contents.gsub(/([0-9\.]+)/, version)
39
+ File.write(version_path, updated_contents)
40
+
41
+ puts "Commiting version update"
42
+ `git add #{version_path}`
43
+ `git commit --message='#{type.capitalize} release #{version}'`
44
+
45
+ puts "Tagging release"
46
+ `git tag -a v#{version} -m 'Version #{version}'`
47
+
48
+ puts "Pushing branch"
49
+ `git push origin master`
50
+
51
+ puts "Pushing tag"
52
+ `git push origin v#{version}`
53
+
54
+ puts "All done, travis should pick up and release the gem now!"
55
+ end
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "cfndsl/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "cfndsl"
8
+ s.version = CfnDsl::VERSION
9
+ s.summary = "AWS Cloudformation DSL"
10
+ s.description = "DSL for creating AWS Cloudformation templates"
11
+ s.authors = ["Steven Jack", "Chris Howe"]
12
+ s.email = ["stevenmajack@gmail.com", "chris@howeville.com"]
13
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
14
+ s.executables << "cfndsl"
15
+ s.homepage = "https://github.com/stevenjack/cfndsl"
16
+ s.license = "MIT"
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency "bundler"
21
+ end
@@ -0,0 +1,3 @@
1
+ module CfnDsl
2
+ VERSION = "0.1.17"
3
+ end
@@ -0,0 +1,243 @@
1
+
2
+ # We start things off by calling the CloudFormation function.
3
+ CloudFormation {
4
+ # Declare the template format version
5
+ AWSTemplateFormatVersion "2010-09-09"
6
+
7
+ # As the DSL is really ruby, we get all of the different
8
+ # ways to quote strings that come with ruby.
9
+ Description %Q/
10
+ Create a multi-az, load balanced, Auto Scaled sample web site. The
11
+ Auto Scaling trigger is based on the CPU utilization of the web
12
+ servers. The AMI is chosen based on the region in which the stack is
13
+ run. This example creates a web service running across all
14
+ availability zones in a region. The instances are load balanced with a
15
+ simple health check. The web site is available on port 80, however,
16
+ the instances can be configured to listen on any port (8888 by
17
+ default).
18
+
19
+ **WARNING** This template creates one or more Amazon EC2
20
+ instances. You will be billed for the AWS resources used if you create
21
+ a stack from this template.
22
+ /
23
+
24
+ # We can declare Parameters anywhere in the CloudFormation
25
+ # block - these will get rolled up into the Parameters container
26
+ # in the output.
27
+ Parameter("InstanceType") {
28
+ Description "Type of EC2 instance to launch"
29
+ Type "String"
30
+ Default "m1.small"
31
+ }
32
+
33
+ Parameter( "WebServerPort") {
34
+ Description "The TCP port for the Web Server"
35
+ Type "String"
36
+ Default "8888"
37
+ }
38
+ Parameter("KeyName") {
39
+ Description "The EC2 Key Pair to allow SSH access to the instances"
40
+ Type "String"
41
+ }
42
+
43
+ # The same kind of thing for parameters works for mappings,
44
+ # except that there is not a special object declared for mappings,
45
+ # so we just have to build a hash of hashes which will be turned
46
+ # directly into json.
47
+
48
+ Mapping("AWSRegionArch2AMI", {
49
+ "us-east-1" => { "32" => "ami-6411e20d", "64" => "ami-7a11e213" },
50
+ "us-west-1" => { "32" => "ami-c9c7978c", "64" => "ami-cfc7978a" },
51
+ "eu-west-1" => { "32" => "ami-37c2f643", "64" => "ami-31c2f645" },
52
+ "ap-southeast-1" => { "32" => "ami-66f28c34", "64" => "ami-60f28c32" },
53
+ "ap-northeast-1" => { "32" => "ami-9c03a89d", "64" => "ami-a003a8a1" }
54
+ })
55
+
56
+
57
+ # We can also write arbitrary ruby code
58
+
59
+ # Here we build up a ruby hash
60
+ architectures = {}
61
+ [ "t1.micro", "m1.large", "m1.xlarge", "m2.xlarge",
62
+ "m2.2xlarge", "m2.4xlarge", "c1.xlarge", "cc1.4xlarge"
63
+ ].each do |arch|
64
+ # Iterate through the 64 bit machines to build a mapping for
65
+ # 64 bit architecture
66
+ architectures[arch] = { "Arch" => "64" }
67
+ end
68
+
69
+ [ "m1.small", "c1.medium"
70
+ ].each do |arch|
71
+ # iterate throught he 32 bit machine to build a mapping for
72
+ # 32 bit architectures
73
+ architectures[arch] = { "Arch" => "32" }
74
+ end
75
+
76
+ Mapping("AWSInstanceType2Arch", architectures )
77
+ # This will add a mapping entry equivalent to the following to the
78
+ # template:
79
+ #
80
+ # "AWSInstanceType2Arch" : {
81
+ # "m2.4xlarge" : { "Arch" : "64" },
82
+ # "c1.xlarge" : { "Arch" : "64" },
83
+ # "c1.medium" : { "Arch" : "32" },
84
+ # "m1.xlarge" : { "Arch" : "64" },
85
+ # "m1.large" : { "Arch" : "64" },
86
+ # "t1.micro" : { "Arch" : "64" },
87
+ # "m1.small" : { "Arch" : "32" },
88
+ # "m2.2xlarge" : { "Arch" : "64" },
89
+ # "m2.xlarge" : { "Arch" : "64" },
90
+ # "cc1.4xlarge" : { "Arch" : "64" }
91
+ # }
92
+
93
+
94
+ # Resources work similar to Parameters
95
+ Resource("WebServerGroup") {
96
+ Type "AWS::AutoScaling::AutoScalingGroup"
97
+
98
+ # To call aws template defined functions, call them like
99
+ # functios (leaving out the double colons). For example
100
+ # the following:
101
+ Property("AvailabilityZones", FnGetAZs("") )
102
+ # will generate JSON that includes
103
+ # { "Fn::GetAZs : "" }
104
+ # as the value of the AvailabilityZones property for the
105
+ # "WebServerGroup" reqource.
106
+
107
+ # The same works for references
108
+ Property("LaunchConfigurationName", Ref( "LaunchConfig") )
109
+ Property("MinSize", "1")
110
+ Property("MaxSize", "3")
111
+
112
+ # If you need to set a property value to a JSON array in
113
+ # the template, you can just use a ruby array in the DSL.
114
+ Property("LoadBalancerNames", [ Ref( "ElasticLoadBalancer") ] )
115
+
116
+ }
117
+
118
+ # You can use either strings or symbols for
119
+ # Resource/Parameter/Mapping/Output names
120
+ Resource( :LaunchConfig ) {
121
+ Type "AWS::AutoScaling::LaunchConfiguration"
122
+
123
+ Property("KeyName", Ref("KeyName") )
124
+ Property( "ImageId",
125
+ FnFindInMap( "AWSRegionArch2AMI", Ref("AWS::Region"),
126
+ FnFindInMap( "AWSInstanceType2Arch", Ref("InstanceType"),"Arch")))
127
+ Property("UserData", FnBase64( Ref("WebServerPort")))
128
+ Property("SecurityGroups", [ Ref("InstanceSecurityGroup")])
129
+ Property("InstanceType", Ref("InstanceType") )
130
+ }
131
+
132
+
133
+ Resource( "WebServerScaleUpPolicy" ) {
134
+ Type "AWS::AutoScaling::ScalingPolicy"
135
+ Property("AdjustmentType", "ChangeInCapacity")
136
+ Property("AutoScalingGroupName", Ref( "WebServerGroup") )
137
+ Property("Cooldown", "60")
138
+ Property("ScalingAdjustment", "1")
139
+ }
140
+
141
+ Resource("WebServerScaleDownPolicy") {
142
+ Type "AWS::AutoScaling::ScalingPolicy"
143
+ Property("AdjustmentType", "ChangeInCapacity")
144
+ Property("AutoScalingGroupName", Ref( "WebServerGroup" ))
145
+ Property("Cooldown", "60")
146
+ Property("ScalingAdjustment", "-1")
147
+ }
148
+
149
+
150
+ # You can use ruby language constructs to keep from repeating
151
+ # yourself
152
+
153
+ # declare an aray - we are going to use it to collect some
154
+ # resources that we create
155
+ alarms = [];
156
+
157
+ # When we declare a resource with "Resource", we are
158
+ # actually calling a method on CfnDsl::CloudFormationTemplate
159
+ # that sets up the resource, and then returns it. We can use
160
+ # the return value for other means.
161
+ alarms.push Resource("CPUAlarmHigh") {
162
+ Type "AWS::CloudWatch::Alarm"
163
+ Property("AlarmDescription", "Scale-up if CPU > 90% for 10 minutes")
164
+ Property("Threshold", "90")
165
+ Property("AlarmActions", [ Ref("WebServerScaleUpPolicy" ) ])
166
+ Property("ComparisonOperator", "GreaterThanThreshold")
167
+ }
168
+
169
+ # Declare a second alarm resource and add it to our list
170
+ alarms.push Resource("CPUAlarmLow") {
171
+ Type "AWS::CloudWatch::Alarm"
172
+ Property("AlarmDescription", "Scale-down if CPU < 70% for 10 minutes")
173
+ Property("Threshold", "70")
174
+ Property("AlarmActions", [ Ref("WebServerScaleDownPolicy" ) ])
175
+ Property("ComparisonOperator", "LessThanThreshold")
176
+ }
177
+
178
+ # Ok, the alarms that we previously declared actually share a bunch
179
+ # of property declarations. Here we iterate through the alarms and
180
+ # call declare on each one, passing in a code block. This works the
181
+ # same as the declarations placed in the code blocks that went along
182
+ # with the call to Resource that was used to create the resouce above.
183
+ alarms.each do |alarm|
184
+ alarm.declare {
185
+ Property("MetricName", "CPUUtilization")
186
+ Property("Namespace", "AWS/EC2")
187
+ Property("Statistic", "Average")
188
+ Property("Period", "300")
189
+ Property("EvaluationPeriods", "2")
190
+ Property("Dimensions", [
191
+ {
192
+ "Name" => "AutoScalingGroupName",
193
+ "Value" => Ref("WebServerGroup" )
194
+ }
195
+ ])
196
+
197
+ }
198
+ end
199
+
200
+
201
+ Resource( "ElasticLoadBalancer" ) {
202
+ Type "AWS::ElasticLoadBalancing::LoadBalancer"
203
+ Property( "AvailabilityZones", FnGetAZs(""))
204
+ Property( "Listeners" , [ {
205
+ "LoadBalancerPort" => "80",
206
+ "InstancePort" => Ref( "WebServerPort" ),
207
+ "Protocol" => "HTTP"
208
+ } ] )
209
+ Property( "HealthCheck" , {
210
+ # FnFormat replaces %0, %1, etc with passed in parameters
211
+ # Note that it renders to a call to Fn::Join in the json.
212
+ "Target" => FnFormat("HTTP:%0/", Ref( "WebServerPort" ) ),
213
+ "HealthyThreshold" => "3",
214
+ "UnhealthyThreshold" => "5",
215
+ "Interval" => "30",
216
+ "Timeout" => "5"
217
+ })
218
+ }
219
+
220
+ Resource("InstanceSecurityGroup" ) {
221
+ Type "AWS::EC2::SecurityGroup"
222
+ Property("GroupDescription" , "Enable SSH access and HTTP access on the inbound port")
223
+ Property("SecurityGroupIngress", [ {
224
+ "IpProtocol" => "tcp",
225
+ "FromPort" => "22",
226
+ "ToPort" => "22",
227
+ "CidrIp" => "0.0.0.0/0"
228
+ },
229
+ {
230
+ "IpProtocol" => "tcp",
231
+ "FromPort" => Ref( "WebServerPort" ),
232
+ "ToPort" => Ref( "WebServerPort" ),
233
+ "SourceSecurityGroupOwnerId" => FnGetAtt("ElasticLoadBalancer", "SourceSecurityGroup.OwnerAlias"),
234
+ "SourceSecurityGroupName" => FnGetAtt("ElasticLoadBalancer", "SourceSecurityGroup.GroupName")
235
+ } ])
236
+ }
237
+
238
+ Output( "URL" ) {
239
+ Description "The URL of the website"
240
+ Value FnJoin( "", [ "http://", FnGetAtt( "ElasticLoadBalancer", "DNSName" ) ] )
241
+ }
242
+
243
+ }