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 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
@@ -1,3 +1,7 @@
1
+ ## v0.2.2
2
+ * Lots of translation updates (AWS -> RS "hot")
3
+ * User Documentation!
4
+
1
5
  ## v0.2.0
2
6
  * Add Registry helper into Utils
3
7
  * Add script for collecting cfn and hot resources
data/Gemfile.lock CHANGED
@@ -1,16 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sparkle_formation (0.2.0)
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.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
+ ```