sparkle_formation 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +2 -4
- data/docs/README.md +177 -0
- data/docs/anatomy.md +203 -0
- data/docs/building-blocks.md +275 -0
- data/docs/examples/cloudformation/components/base.rb +25 -0
- data/docs/examples/cloudformation/dynamics/elb.rb +23 -0
- data/docs/examples/cloudformation/templates/website.rb +30 -0
- data/docs/examples/template_json/website.json +88 -0
- data/docs/examples/website.rb +74 -0
- data/docs/functions.md +41 -0
- data/docs/properties.md +32 -0
- data/docs/provisioning.md +82 -0
- data/docs/resource-reference.md +49 -0
- data/lib/sparkle_formation/sparkle_formation.rb +1 -1
- data/lib/sparkle_formation/translation/heat.rb +84 -1
- data/lib/sparkle_formation/translation/rackspace.rb +355 -11
- data/lib/sparkle_formation/translation.rb +109 -12
- data/lib/sparkle_formation/version.rb +2 -3
- metadata +45 -39
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cba70b56deef5fd41dfd28df337ac9f1af137119
|
4
|
+
data.tar.gz: 08122ae8c40990d331d8be3bbff0b58293162f18
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5fdcff8822399fa54d5274642e865198514607ef84c8eacb70bbe6ab06e86da2fb9fdd97c4092e5abfd2c3a991a4c1bf2c61c8b7f57c31b59c89276ef8604411
|
7
|
+
data.tar.gz: 027bae7862955e2e0d3ff4aac121daa4a4f67a1937850ce62d90a3d3528c6470b3f8f51009ae58989af726c7c06e11400a38826b9a46cbb7e6d220e732bc8a0c
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sparkle_formation (0.2.
|
4
|
+
sparkle_formation (0.2.2)
|
5
5
|
attribute_struct (~> 0.2.2)
|
6
6
|
multi_json
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
attribute_struct (0.2.
|
12
|
-
hashie (>= 2.0.0)
|
13
|
-
hashie (2.1.1)
|
11
|
+
attribute_struct (0.2.8)
|
14
12
|
multi_json (1.10.1)
|
15
13
|
|
16
14
|
PLATFORMS
|
data/docs/README.md
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
## Overview
|
2
|
+
SparkleFormation is a Ruby DSL for programatically composing
|
3
|
+
[AWS Cloudformation][cloudformation], [OpenStack Heat][heat]
|
4
|
+
provisioning templates for the purpose of interacting with cloud
|
5
|
+
infrastructure orchestration APIs.
|
6
|
+
|
7
|
+
SparkleFormation templates describe the creation and configuration of
|
8
|
+
collections of cloud resources (a stack) as code, allowing you to
|
9
|
+
provision stacks in a predictable and repeatable manner. Stacks can be
|
10
|
+
managed as single unit, allowing you to create, modify, or delete
|
11
|
+
collections of resources via a single API call.
|
12
|
+
|
13
|
+
SparkleFormation composes templates in the native cloud orchestration
|
14
|
+
formats for AWS, Rackspace, Google Compute, and similar services.
|
15
|
+
|
16
|
+
## Table of Contents
|
17
|
+
|
18
|
+
- [Getting Started](#getting-started)
|
19
|
+
- [What It Looks Like](#what-it-looks-like)
|
20
|
+
- [Building Blocks](building-blocks.md)
|
21
|
+
- [Components](building-blocks.md#components)
|
22
|
+
- [Dynamics](building-blocks.md#dynamics)
|
23
|
+
- [Registries](building-blocks.md#registries)
|
24
|
+
- [Template Anatomy](anatomy.md)
|
25
|
+
- [Parameters](anatomy.md#parameters)
|
26
|
+
- [Resources](anatomy.md#resources)
|
27
|
+
- [Mappings](anatomy.md#mappings)
|
28
|
+
- [Outputs](anatomy.md#outputs)
|
29
|
+
- [Intrinsic Functions](functions.md)
|
30
|
+
- [Ref](functions.md#ref)
|
31
|
+
- [Attr](functions.md#attr)
|
32
|
+
- [Join](functions.md#join)
|
33
|
+
- [Universal Properties](properties.md)
|
34
|
+
- [Tags](properties.md#tags)
|
35
|
+
|
36
|
+
## Getting Started
|
37
|
+
### Gemfile
|
38
|
+
SparkleFormation is in active development. To access all the features
|
39
|
+
detailed in the documentation (using the knife plugin CLI), you should
|
40
|
+
install the plugin and supporting libraries from git:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
gem 'fog', :git => 'https://github.com/chrisroberts/fog.git', :ref => 'feature/orchestration'
|
44
|
+
gem 'fog-core', :git => 'https://github.com/chrisroberts/fog-core.git', :ref => 'feature/orchestration'
|
45
|
+
gem 'knife-cloudformation', :git => 'https://github.com/heavywater/knife-cloudformation.git', :ref => 'feature/fog-model'
|
46
|
+
```
|
47
|
+
|
48
|
+
The Knife Cloudformation gem is only needed for stack provisioning via
|
49
|
+
knife. You could also upload SparkleFormation generated templates to AWS via the WebUI.
|
50
|
+
|
51
|
+
### Knife Config
|
52
|
+
To use Knife for provisioning, you will need to add the following to
|
53
|
+
your `knife.rb` file:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
knife[:aws_access_key_id] = ENV['AWS_ACCESS_KEY_ID']
|
57
|
+
knife[:aws_secret_access_key] = ENV['AWS_SECRET_ACCESS_KEY']
|
58
|
+
|
59
|
+
[:cloudformation, :options].inject(knife){ |m,k| m[k] ||= Mash.new }
|
60
|
+
knife[:cloudformation][:options][:disable_rollback] = ENV['AWS_CFN_DISABLE_ROLLBACK'].to_s.downcase == 'true'
|
61
|
+
knife[:cloudformation][:options][:capabilities] = ['CAPABILITY_IAM']
|
62
|
+
knife[:cloudformation][:processing] = true
|
63
|
+
knife[:cloudformation][:credentials] = {
|
64
|
+
:aws_access_key_id => knife[:aws_access_key_id],
|
65
|
+
:aws_secret_access_key => knife[:aws_secret_access_key]
|
66
|
+
}
|
67
|
+
```
|
68
|
+
|
69
|
+
| Attribute | Function |
|
70
|
+
|--------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
|
71
|
+
| `[:cloudformation][:options][:disable_rollback]` | Disables rollback if stack is unsuccessful. Useful for debugging. |
|
72
|
+
| `[:cloudformation][:credentials]` | Credentials for a user that is allowed to create stacks. |
|
73
|
+
| `[:cloudformation][:options][:capabilities]` | Enables IAM creation (AWS only). Options are `nil` or `['CAPABILITY_IAM']` |
|
74
|
+
| `[:cloudformation][:processing]` | Enables processing SparkleFormation templates (otherwise knife cloudformation will expect a JSON CFN template. |
|
75
|
+
|
76
|
+
## What it Looks Like
|
77
|
+
Below is a basic SparkleFormation template which would provision an
|
78
|
+
elastic load balancer forwarding port 80 to an autoscaling group of
|
79
|
+
ec2 instances.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
SparkleFormation.new('website') do
|
83
|
+
|
84
|
+
set!('AWSTemplateFormatVersion', '2010-09-09')
|
85
|
+
|
86
|
+
description 'Supercool Website'
|
87
|
+
|
88
|
+
resources.cfn_user do
|
89
|
+
type 'AWS::IAM::User'
|
90
|
+
properties.path '/'
|
91
|
+
properties.policies _array(
|
92
|
+
-> {
|
93
|
+
policy_name 'cfn_access'
|
94
|
+
policy_document.statement _array(
|
95
|
+
-> {
|
96
|
+
effect 'Allow'
|
97
|
+
action 'cloudformation:DescribeStackResource'
|
98
|
+
resource '*'
|
99
|
+
}
|
100
|
+
)
|
101
|
+
}
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
resources.cfn_keys do
|
106
|
+
type 'AWS::IAM::AccessKey'
|
107
|
+
properties.user_name ref!(:cfn_user)
|
108
|
+
end
|
109
|
+
|
110
|
+
parameters.web_nodes do
|
111
|
+
type 'Number'
|
112
|
+
description 'Number of web nodes for ASG.'
|
113
|
+
default 2
|
114
|
+
end
|
115
|
+
|
116
|
+
resources.website_autoscale do
|
117
|
+
type 'AWS::AutoScaling::AutoScalingGroup'
|
118
|
+
properties do
|
119
|
+
availability_zones({'Fn::GetAZs' => ''})
|
120
|
+
launch_configuration_name ref!(:website_launch_config)
|
121
|
+
min_size ref!(:web_nodes)
|
122
|
+
max_size ref!(:web_nodes)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
resources.website_launch_config do
|
127
|
+
type 'AWS::AutoScaling::LaunchConfiguration'
|
128
|
+
properties do
|
129
|
+
image_id 'ami-123456'
|
130
|
+
instance_type 'm3.medium'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
resources.website_elb do
|
135
|
+
type 'AWS::ElasticLoadBalancing::LoadBalancer'
|
136
|
+
properties do
|
137
|
+
availability_zones._set('Fn::GetAZs', '')
|
138
|
+
listeners _array(
|
139
|
+
-> {
|
140
|
+
load_balancer_port '80'
|
141
|
+
protocol 'HTTP'
|
142
|
+
instance_port '80'
|
143
|
+
instance_protocol 'HTTP'
|
144
|
+
}
|
145
|
+
)
|
146
|
+
health_check do
|
147
|
+
target 'HTTP:80/'
|
148
|
+
healthy_threshold '3'
|
149
|
+
unhealthy_threshold '3'
|
150
|
+
interval '5'
|
151
|
+
timeout '15'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
This template is 74 lines long (with generous spacing for
|
159
|
+
readability). The [json template this
|
160
|
+
renders](examples/template_json/website.json) is 88 lines, without
|
161
|
+
spacing). This can be improved, though. SparkleFormation allows you to
|
162
|
+
create resusable files such that the above template can become :
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
SparkleFormation.new(:website).load(:base).overrides do
|
166
|
+
|
167
|
+
description 'Supercool Website'
|
168
|
+
|
169
|
+
dynamic!(:autoscale, 'website', :nodes => 2)
|
170
|
+
dynamic!(:launch_config, 'website', :image_id => 'ami-123456', :instance_type => 'm3.medium')
|
171
|
+
dynamic!(:elb, 'website')
|
172
|
+
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
176
|
+
[cloudformation]: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-guide.html
|
177
|
+
[heat]: http://docs.openstack.org/developer/heat/template_guide/index.html
|
data/docs/anatomy.md
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
## Template Anatomy
|
2
|
+
|
3
|
+
### Parameters
|
4
|
+
Parameters are prompts for stack specific values. A default may be
|
5
|
+
specified, but is not required. Every parameter must have a value at runtime.
|
6
|
+
|
7
|
+
In the Getting Started example we had one parameter, `web_nodes` which
|
8
|
+
set the min and max for the autoscaling group:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
parameters.web_nodes do
|
12
|
+
type 'Number'
|
13
|
+
description 'Number of web nodes for ASG.'
|
14
|
+
default 2
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
Every parameter must have a type and a description. Available types are `String`,
|
19
|
+
`Number` (an integer), and `CommaDelimitedList` (an array of
|
20
|
+
strings, as-in: `['alpha', 'beta', '1', 2']`). The descriptions is a
|
21
|
+
string describing the resource.
|
22
|
+
|
23
|
+
Parameters support optional default values, declared as
|
24
|
+
above. An array of accepted values may be set, as well:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
parameters.web_nodes do
|
28
|
+
type 'Number'
|
29
|
+
description 'Number of web nodes for ASG.'
|
30
|
+
default 2
|
31
|
+
allowed_values [1, 2, 3, 5]
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
### Resources
|
36
|
+
Resources are the infrastructure resources that are provisioned with
|
37
|
+
the stack. Every resource must have a type that corresponds to a
|
38
|
+
supported cloud resource. Resources typically have a properties hash
|
39
|
+
that configures the resource. Some resources also have metadata. For
|
40
|
+
the complete list of required and optional options, see the
|
41
|
+
individual resource documentation.
|
42
|
+
|
43
|
+
Resource availability is not consistent across
|
44
|
+
providers. SparkleFormation's resources support is based on AWS, and
|
45
|
+
not all resources will be available on other platforms. See the
|
46
|
+
[resource reference](resource-reference.md) table for more information.
|
47
|
+
|
48
|
+
The prior example included the following resources:
|
49
|
+
- cfn_user: The IAM user for the stack, which will be used to
|
50
|
+
provision stack resources.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
resources.cfn_user do
|
54
|
+
type 'AWS::IAM::User'
|
55
|
+
properties.path '/'
|
56
|
+
properties.policies _array(
|
57
|
+
-> {
|
58
|
+
policy_name 'cfn_access'
|
59
|
+
policy_document.statement _array(
|
60
|
+
-> {
|
61
|
+
effect 'Allow'
|
62
|
+
action 'cloudformation:DescribeStackResource'
|
63
|
+
resource '*'
|
64
|
+
}
|
65
|
+
)
|
66
|
+
}
|
67
|
+
)
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
- cfn_key: The IAM keys for the stack IAM user.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
resources.cfn_keys do
|
75
|
+
type 'AWS::IAM::AccessKey'
|
76
|
+
properties.user_name ref!(:cfn_user)
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
- website_asg: The autoscaling group containing website nodes. The
|
81
|
+
size of the autoscaling group is set to the value of the web_nodes
|
82
|
+
parameter.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
resources.website_autoscale do
|
86
|
+
type 'AWS::AutoScaling::AutoScalingGroup'
|
87
|
+
properties do
|
88
|
+
availability_zones({'Fn::GetAZs' => ''})
|
89
|
+
launch_configuration_name ref!(:website_launch_config)
|
90
|
+
min_size ref!(:web_nodes)
|
91
|
+
max_size ref!(:web_nodes)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
- website_launch_configuration: The launch configuration for
|
97
|
+
website_asg nodes. The AMI image ID and instance type (size) are
|
98
|
+
required.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
resources.website_launch_config do
|
102
|
+
type 'AWS::AutoScaling::LaunchConfiguration'
|
103
|
+
properties do
|
104
|
+
image_id 'ami-123456'
|
105
|
+
instance_type 'm3.medium'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
- website_elb: The elastic load balancer for the website. The
|
111
|
+
listeners array configures port forwarding. The health check
|
112
|
+
configures the load balancer health check target and thresholds.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
resources.website_elb do
|
116
|
+
type 'AWS::ElasticLoadBalancing::LoadBalancer'
|
117
|
+
properties do
|
118
|
+
availability_zones._set('Fn::GetAZs', '')
|
119
|
+
listeners _array(
|
120
|
+
-> {
|
121
|
+
load_balancer_port '80'
|
122
|
+
protocol 'HTTP'
|
123
|
+
instance_port '80'
|
124
|
+
instance_protocol 'HTTP'
|
125
|
+
}
|
126
|
+
)
|
127
|
+
health_check do
|
128
|
+
target 'HTTP:80/'
|
129
|
+
healthy_threshold '3'
|
130
|
+
unhealthy_threshold '3'
|
131
|
+
interval '5'
|
132
|
+
timeout '15'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
### Mappings
|
139
|
+
Mappings allow you to create key/value pairs which can be referenced
|
140
|
+
at runtime. This is useful for things like an image id that differs
|
141
|
+
by region or environment.
|
142
|
+
|
143
|
+
Mappings for the 2014.09 Amazon Linux PV Instance Store 64-bit AMIs
|
144
|
+
for each US region:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
mappings.region_map do
|
148
|
+
set!('us-east-1', :ami => 'ami-8e852ce6')
|
149
|
+
set!('us-west-1', :ami => 'ami-03a8a146')
|
150
|
+
set!('us-west-2', :ami => 'ami-f786c6c7')
|
151
|
+
end
|
152
|
+
```
|
153
|
+
|
154
|
+
These can be referenced, in turn, with the following:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
map!(:region_map, ref!('AWS::Region'), :ami)
|
158
|
+
```
|
159
|
+
|
160
|
+
'AWS::Region' is a psuedo parameter. We could also perform a lookup
|
161
|
+
based on a parameter we provide, e.g. an instance size based on the environment:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
parameters.environment do
|
165
|
+
type 'String'
|
166
|
+
allowed_values ['development', 'staging', 'production']
|
167
|
+
end
|
168
|
+
|
169
|
+
mappings.instance_size do
|
170
|
+
set!('development', :instance => 'm3.small')
|
171
|
+
set!('staging', :instance => 'm3.medium')
|
172
|
+
set!('production', :instance => 'm3.large')
|
173
|
+
end
|
174
|
+
|
175
|
+
resources.website_launch_config do
|
176
|
+
type 'AWS::AutoScaling::LaunchConfiguration'
|
177
|
+
properties do
|
178
|
+
image_id map!(:region_map, 'AWS::Region', :ami)
|
179
|
+
instance_type map!(:instance_size, ref!(:environment), :instance)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
### Outputs
|
185
|
+
Outputs provide metadata for the stack, as key/value pairs within an
|
186
|
+
outputs block. Note that this block lives outside the resource
|
187
|
+
blocks. This will retrieve the DNSName attribute for our load
|
188
|
+
balancer, and provide it as a value for an 'Elb Dns' output:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
outputs do
|
192
|
+
elb_dns do
|
193
|
+
value attr!(:website_elb, 'DNSName')
|
194
|
+
description "Website ELB DNS name"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
199
|
+
Outputs are not simply informational. You can interact with them
|
200
|
+
during [provisioning](provisioning.md#knife-cloudformation) using the [knife-cloudformation
|
201
|
+
plugin](https://rubygems.org/gems/knife-cloudformation).
|
202
|
+
|
203
|
+
|
@@ -0,0 +1,275 @@
|
|
1
|
+
## SparkleFormation Building Blocks
|
2
|
+
|
3
|
+
Using SparkleFormation for the above template has already saved us
|
4
|
+
many keystrokes, but what about reusing SparkleFormation code between
|
5
|
+
similar stacks? This is where SparkleFormation concepts like
|
6
|
+
components, dynamics, and registries come into play.
|
7
|
+
|
8
|
+
### Components
|
9
|
+
|
10
|
+
Components are static configuration which can be reused between many
|
11
|
+
stack templates. In our example case we have decided that all our
|
12
|
+
stacks will need to make use of IAM credentials, so we will create
|
13
|
+
a component which allows us to inserts the two IAM resources into any
|
14
|
+
template in a resuable fashion. The component, which we will call
|
15
|
+
'base' and put in a file called 'base.rb,' would look like this:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
SparkleFormation.build do
|
19
|
+
set!('AWSTemplateFormatVersion', '2010-09-09')
|
20
|
+
|
21
|
+
resources.cfn_user do
|
22
|
+
type 'AWS::IAM::User'
|
23
|
+
properties.path '/'
|
24
|
+
properties.policies _array(
|
25
|
+
-> {
|
26
|
+
policy_name 'cfn_access'
|
27
|
+
policy_document.statement _array(
|
28
|
+
-> {
|
29
|
+
effect 'Allow'
|
30
|
+
action 'cloudformation:DescribeStackResource'
|
31
|
+
resource '*'
|
32
|
+
}
|
33
|
+
)
|
34
|
+
}
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
resources.cfn_keys do
|
39
|
+
type 'AWS::IAM::AccessKey'
|
40
|
+
properties.user_name ref!(:cfn_user)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
After moving these resources out of the initial template and into a
|
46
|
+
component, we will update the template so that the base component is
|
47
|
+
loaded on the first line, and the resources it contains are no longer
|
48
|
+
present in the template itself:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
SparkleFormation.new(:website).load(:base).overrides do
|
52
|
+
|
53
|
+
description 'Supercool Website'
|
54
|
+
|
55
|
+
parameters.web_nodes do
|
56
|
+
type 'Number'
|
57
|
+
description 'Number of web nodes for ASG.'
|
58
|
+
default '2'
|
59
|
+
end
|
60
|
+
|
61
|
+
resources.website_autoscale do
|
62
|
+
type 'AWS::AutoScaling::AutoScalingGroup'
|
63
|
+
properties do
|
64
|
+
availability_zones({'Fn::GetAZs' => ''})
|
65
|
+
launch_configuration_name ref!(:website_launch_config)
|
66
|
+
min_size ref!(:web_nodes)
|
67
|
+
max_size ref!(:web_nodes)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
resources.website_launch_config do
|
72
|
+
type 'AWS::AutoScaling::LaunchConfiguration'
|
73
|
+
properties do
|
74
|
+
image_id 'ami-123456'
|
75
|
+
instance_type 'm3.medium'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
resources.website_elb do
|
80
|
+
type 'AWS::ElasticLoadBalancing::LoadBalancer'
|
81
|
+
properties do
|
82
|
+
availability_zones._set('Fn::GetAZs', '')
|
83
|
+
listeners _array(
|
84
|
+
-> {
|
85
|
+
load_balancer_port '80'
|
86
|
+
protocol 'HTTP'
|
87
|
+
instance_port '80'
|
88
|
+
instance_protocol 'HTTP'
|
89
|
+
}
|
90
|
+
)
|
91
|
+
health_check do
|
92
|
+
target 'HTTP:80/'
|
93
|
+
healthy_threshold '3'
|
94
|
+
unhealthy_threshold '3'
|
95
|
+
interval '5'
|
96
|
+
timeout '15'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
### Dynamics
|
104
|
+
|
105
|
+
Like components, dynamics are another SparkleFormation feature which
|
106
|
+
enables code reuse between stack templates. Where components are
|
107
|
+
static, dynamics are useful for creating unique resources via
|
108
|
+
the passing of arguments.
|
109
|
+
|
110
|
+
In our example scenario we have decided that we want to use elastic
|
111
|
+
load balancer resources in many of our stack templates, we want to
|
112
|
+
create a dynamic which makes inserting ELB resources much easier than
|
113
|
+
copying the full resource configuration between templates.
|
114
|
+
|
115
|
+
The resulting implementation would look something like this:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
SparkleFormation.dynamic(:elb) do |_name, _config={}|
|
119
|
+
resources("#{_name}_elb".to_sym) do
|
120
|
+
type 'AWS::ElasticLoadBalancing::LoadBalancer'
|
121
|
+
properties do
|
122
|
+
availability_zones._set('Fn::GetAZs', '')
|
123
|
+
listeners _array(
|
124
|
+
-> {
|
125
|
+
load_balancer_port _config[:load_balancer_port] || '80'
|
126
|
+
protocol _config[:protocol] || 'HTTP'
|
127
|
+
instance_port _config[:instance_port] || '80'
|
128
|
+
instance_protocol _config[:instance_protocol] || 'HTTP'
|
129
|
+
}
|
130
|
+
)
|
131
|
+
health_check do
|
132
|
+
target _config[:target] || 'HTTP:80/'
|
133
|
+
healthy_threshold _config[:healthy_threshold] || '3'
|
134
|
+
unhealthy_threshold _config[:unhealthy_threshold] || '3'
|
135
|
+
interval _config[:interval] || '5'
|
136
|
+
timeout _config[:timeout] || '15'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
This dynamic accepts two arguments: `_name` (a string, required) and `_config`
|
144
|
+
(a hash, optional). The dynamic will use the values passed in these
|
145
|
+
arguments to generate a new ELB resource, and override the default ELB
|
146
|
+
properties wherever a corresponding key/value pair is provided in the
|
147
|
+
`_config` hash.
|
148
|
+
|
149
|
+
Once updated to make use of the new ELB dynamic, our template looks
|
150
|
+
like this:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
SparkleFormation.new(:website).load(:base).overrides do
|
154
|
+
|
155
|
+
description 'Supercool Website'
|
156
|
+
|
157
|
+
parameters.web_nodes do
|
158
|
+
type 'Number'
|
159
|
+
description 'Number of web nodes for ASG.'
|
160
|
+
default '2'
|
161
|
+
end
|
162
|
+
|
163
|
+
resources.website_autoscale do
|
164
|
+
type 'AWS::AutoScaling::AutoScalingGroup'
|
165
|
+
properties do
|
166
|
+
availability_zones({'Fn::GetAZs' => ''})
|
167
|
+
launch_configuration_name ref!(:website_launch_config)
|
168
|
+
min_size ref!(:web_nodes)
|
169
|
+
max_size ref!(:web_nodes)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
resources.website_launch_config do
|
174
|
+
type 'AWS::AutoScaling::LaunchConfiguration'
|
175
|
+
properties do
|
176
|
+
image_id 'ami-123456'
|
177
|
+
instance_type 'm3.medium'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
dynamic!(:elb, 'website')
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
If we wanted to override the default configuration for the ELB,
|
186
|
+
e.g. to configure the ELB to listen on and communicate with back-end
|
187
|
+
node on port 8080 instead of 80, we can specify these override values
|
188
|
+
in the configuration passed to the ELB dynamic:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
dynamic!(:elb, 'website', :load_balancer_port => 8080, :instance_port => 8080)
|
192
|
+
```
|
193
|
+
|
194
|
+
We're passing three arguments here:
|
195
|
+
|
196
|
+
1. `:elb` is the name of the dynamic to insert, as a ruby symbol
|
197
|
+
2. A name string (`'website'`), which is passed to `_name` in the
|
198
|
+
dynamic. This is prepended to the resource name in the dynamic,
|
199
|
+
resulting in a unique resource name.
|
200
|
+
3. The ELB ports to configure as key/value pairs. These are passed into the dynamic as
|
201
|
+
the `_config` hash.
|
202
|
+
|
203
|
+
### Registries
|
204
|
+
|
205
|
+
Similar to dynamics, registries are reusable resource configuration
|
206
|
+
code which can be reused inside different resource definitions.
|
207
|
+
|
208
|
+
Registries are useful for defining properties that may be reused
|
209
|
+
between resources of different types. For example, the
|
210
|
+
LaunchConfiguration and Instance resource types make use of metadata
|
211
|
+
properties which inform both resource types how to bootstrap one or
|
212
|
+
more instances.
|
213
|
+
|
214
|
+
In our example scenario we would like our new instances to run
|
215
|
+
'sudo apt-get update && sudo apt-get upgrade -y' at first boot,
|
216
|
+
regardless of whether or not the instances are members of an
|
217
|
+
autoscaling group.
|
218
|
+
|
219
|
+
Because these resources are of different types, placing the metadata
|
220
|
+
required for this task directly inside a dynamic isn't going to work
|
221
|
+
quite the way we need. Instead we can put this inside a registry which
|
222
|
+
can be inserted into the resources defined in one or more dynamics:
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
SparkleFormation::Registry.register(:apt_get_update) do
|
226
|
+
metadata('AWS::CloudFormation::Init') do
|
227
|
+
_camel_keys_set(:auto_disable) do
|
228
|
+
commands('01_apt_get_update') do
|
229
|
+
command 'sudo apt-get update'
|
230
|
+
end
|
231
|
+
commands('02_apt_get_upgrade') do
|
232
|
+
command 'sudo apt-get upgrade -y'
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
Now we can insert this registry entry into our existing template, to
|
239
|
+
ensure that apt is updated upon provisioning:
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
SparkleFormation.new(:website).load(:base).overrides do
|
243
|
+
|
244
|
+
description 'Supercool Website'
|
245
|
+
|
246
|
+
parameters.web_nodes do
|
247
|
+
type 'Number'
|
248
|
+
description 'Number of web nodes for ASG.'
|
249
|
+
default 2
|
250
|
+
end
|
251
|
+
|
252
|
+
resources.website_autoscale do
|
253
|
+
type 'AWS::AutoScaling::AutoScalingGroup'
|
254
|
+
properties do
|
255
|
+
availability_zones({'Fn::GetAZs' => ''})
|
256
|
+
launch_configuration_name ref!(:website_launch_config)
|
257
|
+
min_size ref!(:web_nodes)
|
258
|
+
max_size ref!(:web_nodes)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
resources.website_launch_config do
|
263
|
+
type 'AWS::AutoScaling::LaunchConfiguration'
|
264
|
+
registry!(:apt_get_update, 'website')
|
265
|
+
properties do
|
266
|
+
image_id 'ami-123456'
|
267
|
+
instance_type 'm3.medium'
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
dynamic!(:elb, 'website')
|
272
|
+
|
273
|
+
registry!(:apt_get_update, 'website')
|
274
|
+
end
|
275
|
+
```
|