sparkle_formation 0.2.0 → 0.2.2
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/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
|
+
```
|