sparkle_formation 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a7ac537659ebf74662bbcfff4803d88c1dedfc8
4
- data.tar.gz: f87846f1473c7b2557121b125243829dad134edd
3
+ metadata.gz: 607eb52a5d461c5cf623e017888bb5dc113a3c7e
4
+ data.tar.gz: 45401a5dabb03744b24777538a9548a8ea0e06f0
5
5
  SHA512:
6
- metadata.gz: 8710305f6ca7f5e96e987c87c2896451641d3a9469f5c0d3c1bb1a283b6c7ed1a09759979d014fd447862c689eb815b870ac7462d4c10a106b1659623eb8e7b3
7
- data.tar.gz: 903bbd84d290e38b3273858dd16260e866c95a62085d4d12441c6b6ff007b1412f18f421ccd03d12d22398f878a39527943458893db0ef1f7f24e33550a7a857
6
+ metadata.gz: 565402fe9c3256b0ddcd028c4a1244350796d46d951c97d214f2d97ee7d532709b05654fb26f4a3b503e7316577d7745258f5944d7c2a07b6c1f362c838c6176
7
+ data.tar.gz: fe0d0a5f94ddaf1b5eac0a68840b980fb82990ccb388630ed9723c4e4ea10e9e88810767128b974824d28014e6289f06033c7628c213e1d5155e79dadc8f94ed
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## v1.1.0
2
+ * Add support for compile time parameters
3
+ * Fix usage of deprecated `SparkleFormation.insert` method
4
+ * Propagate parent stack parameter when output required output is in parent stack
5
+
1
6
  ## v1.0.4
2
7
  * Fixes on testing (#66 #67 #68 thanks @matschaffer)
3
8
  * Properly handle JSON templates within packs (#72)
data/docs/README.md ADDED
@@ -0,0 +1,28 @@
1
+ ## Table of Contents
2
+
3
+ - [Getting Started](overview.md#getting-started)
4
+ - [Installation](overview.md#installation)
5
+ - [The DSL](sparkleformation-dsl.md)
6
+ - [Behavior](sparkleformation-dsl.md#behavior)
7
+ - [Features](sparkleformation-dsl.md#features)
8
+ - [Building Blocks](building-blocks.md)
9
+ - [Components](building-blocks.md#components)
10
+ - [Dynamics](building-blocks.md#dynamics)
11
+ - [Registry](building-blocks.md#registry)
12
+ - [Templates](building-blocks.md#templates)
13
+ - [Template Anatomy](anatomy.md)
14
+ - [Base Attributes](anatomy.md#base-attributes)
15
+ - [Parameters](anatomy.md#parameters)
16
+ - [Mappings](anatomy.md#mappings)
17
+ - [Conditions](anatomy.md#conditions)
18
+ - [Resources](anatomy.md#resources)
19
+ - [Outputs](anatomy.md#outputs)
20
+ - Library Features
21
+ - [Helper Methods](helper-methods.md)
22
+ - [Nested Stacks](nested-stacks.md)
23
+ - [Shallow Nesting](nested-stacks.md#shallow-nesting)
24
+ - [Deep Nesting](nested-stacks.md#deep-nesting)
25
+ - [Sparkle Packs](sparkle-packs.md)
26
+ - [Stack Policies](stack-policies.md)
27
+ - [Translation](translation.md)
28
+ - [Compile Time Parameters](compile-time-parameters.md)
data/docs/anatomy.md ADDED
@@ -0,0 +1,205 @@
1
+ ---
2
+ title: "Template Anatomy"
3
+ category: "dsl"
4
+ weight: 4
5
+ anchors:
6
+ - title: "Parameters"
7
+ url: "#parameters"
8
+ - title: "Mappings"
9
+ url: "#mappings"
10
+ - title: "Conditions"
11
+ url: "#conditions"
12
+ - title: "Resources"
13
+ url: "#resources"
14
+ - title: "Outputs"
15
+ url: "#outputs"
16
+ ---
17
+
18
+ ## Template Anatomy
19
+
20
+ The anatomy of a template is dependent on the specific implementation that is
21
+ targeted. Due to the freeform nature of the SparkleFormation DSL any orchestration
22
+ API accepting a serialized document to describe resources is inherently supported.
23
+ Due to that fact, this document will focus directly on the AWS CloudFormation
24
+ style template as it is the most widely implemented.
25
+
26
+ ### AWS CloudFormation in SparkleFormation
27
+
28
+ - [Base Attributes](#base-attributes)
29
+ - [Parameters](#parameters)
30
+ - [Mappings](#mappings)
31
+ - [Conditions](#conditions)
32
+ - [Resources](#resources)
33
+ - [Outputs](#outputs)
34
+
35
+ #### Base Attributes
36
+
37
+ All templates must begin with the expected API version and may include a description
38
+ and or metadata:
39
+
40
+ ~~~ruby
41
+ SparkleFormation.new(:template) do
42
+ set!('AWSTemplateFormatVersion', '2010-09-09')
43
+ description 'My New Stack'
44
+ metadata.instances.description 'Awesome instances'
45
+ end
46
+ ~~~
47
+
48
+ * [Format Version](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html)
49
+ * [Description](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-description-structure.html)
50
+ * [Metadata](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html)
51
+
52
+ #### Parameters
53
+
54
+ Parameters are named variables available within the template that users may
55
+ provide customized values when creating or updating a stack. This allows
56
+ "runtime" modifications to occur when the template is evaluated by the API.
57
+
58
+ ~~~ruby
59
+ SparkleFormation.new(:template) do
60
+ parameters do
61
+ creator do
62
+ type 'String'
63
+ default ENV['USER']
64
+ end
65
+ end
66
+ end
67
+ ~~~
68
+
69
+ * [Parameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html)
70
+
71
+ #### Mappings
72
+
73
+ Mappings are a nested key/value store. They provide an easy way to dynamically
74
+ specify what value should be used based on context available when the template
75
+ is evaluated by the API.
76
+
77
+ ~~~ruby
78
+ SparkleFormation.new(:template) do
79
+ mappings.platforms.set!('us-west-2'._no_hump) do
80
+ centos6 'ami-b6bdde86'
81
+ centos7 'ami-c7d092f7'
82
+ end
83
+ end
84
+ ~~~
85
+
86
+ These can then be referenced using the `map!` helper method:
87
+
88
+ ~~~ruby
89
+ SparkleFormation.new(:template) do
90
+ dynamic!(:ec2_instance, :foobar) do
91
+ properties.image_id map!(:platforms, region!, :centos7)
92
+ end
93
+ end
94
+ ~~~
95
+
96
+ * [Mappings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html)
97
+ * [Fn::FindInMap](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html)
98
+
99
+ #### Conditions
100
+
101
+ Named conditions are defined in this section and then referenced
102
+ elsewhere in the template. Conditions can be used to customize resource
103
+ properties values or to allow/restrict the creation of resources and
104
+ outputs.
105
+
106
+
107
+ ~~~ruby
108
+ SparkleFormation.new(:template) do
109
+ parameters.creator do
110
+ type 'String'
111
+ default 'spox'
112
+ end
113
+ conditions do
114
+ creator_is_spox equals!(ref!(:creator), 'spox')
115
+ end
116
+ end
117
+ ~~~
118
+
119
+ This condition can then be used to provide a custom value for a property:
120
+
121
+ ~~~ruby
122
+ SparkleFormation.new(:template) do
123
+ parameters.creator do
124
+ type 'String'
125
+ default 'spox'
126
+ end
127
+ conditions do
128
+ creator_is_spox equals!(ref!(:creator), 'spox')
129
+ end
130
+ dynamic!(:ec2_instance, :fubar).properties do
131
+ key_name if!(:creator_is_spox, 'spox-key', 'default')
132
+ end
133
+ end
134
+ ~~~
135
+
136
+ The condition can also be used to restrict the creation of a resource:
137
+
138
+ ~~~ruby
139
+ SparkleFormation.new(:template) do
140
+ parameters.creator do
141
+ type 'String'
142
+ default 'spox'
143
+ end
144
+ conditions do
145
+ creator_is_spox equals!(ref!(:creator), 'spox')
146
+ end
147
+ dynamic!(:ec2_instance, :fubar) do
148
+ on_condition :creator_is_spox
149
+ end
150
+ end
151
+ ~~~
152
+
153
+ * [Conditions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html)
154
+ * [Condition Functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html)
155
+
156
+ #### Resources
157
+
158
+ Resources are the infrastructure items and configurations to be
159
+ provisioned by the orchestration API:
160
+
161
+ ~~~ruby
162
+ SparkleFormation.new(:template) do
163
+ resources.my_instance do
164
+ type 'AWS::EC2::Instance'
165
+ properties do
166
+ key_name 'default'
167
+ ...
168
+ end
169
+ end
170
+ end
171
+ ~~~
172
+
173
+ * [Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html)
174
+
175
+ #### Outputs
176
+
177
+ Outputs are resultant values from the provisioned infrastructure stack.
178
+ It generally contains information about specific resource attributes.
179
+
180
+ ~~~ruby
181
+ SparkleFormation.new(:template) do
182
+ outputs do
183
+ instance_address do
184
+ description 'Public IP of my instance'
185
+ value attr!(:my_instance, :public_ip)
186
+ end
187
+ end
188
+ end
189
+ ~~~
190
+
191
+ Conditions can also be applied on outputs:
192
+
193
+ ~~~ruby
194
+ SparkleFormation.new(:template) do
195
+ outputs do
196
+ instance_address do
197
+ description 'Public IP of my instance'
198
+ value attr!(:my_instance, :public_ip)
199
+ on_condition! :my_condition
200
+ end
201
+ end
202
+ end
203
+ ~~~
204
+
205
+ * [Outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html)
@@ -0,0 +1,360 @@
1
+ ---
2
+ title: "SparkleFormation Building Blocks"
3
+ category: "dsl"
4
+ weight: 3
5
+ anchors:
6
+ - title: "Components"
7
+ url: "#components"
8
+ - title: "Dynamics"
9
+ url: "#dynamics"
10
+ - title: "Registry"
11
+ url: "#registry"
12
+ - title: "Templates"
13
+ url: "#templates"
14
+ ---
15
+
16
+ ## SparkleFormation Building Blocks
17
+
18
+ ### Building Blocks
19
+
20
+ SparkleFormation provides a collection of building blocks to
21
+ assist in applying [DRY][1] concepts to template generation. The
22
+ building blocks provided by SparkleFormation are:
23
+
24
+ - [Components](#components)
25
+ - [Dynamics](#dynamics)
26
+ - [Registry](#registry)
27
+ - [Templates](#templates)
28
+
29
+ ### Components
30
+
31
+ Components are static pieces of template that are inserted once.
32
+ They do not provide any dynamic functionality and are intended
33
+ for common static content. Components are the second set of items
34
+ loaded during template compilation and are evaluated in the order
35
+ defined.
36
+
37
+ An example component for an AWS CloudFormation based implementation
38
+ may contain the template versioning information and a common stack
39
+ output value:
40
+
41
+ ~~~ruby
42
+ SparkleFormation.component(:common) do
43
+ set!('AWSTemplateFormatVersion', '2010-09-09')
44
+
45
+ outputs.creator do
46
+ description 'Stack creator'
47
+ value ENV['USER']
48
+ end
49
+ end
50
+ ~~~
51
+
52
+ There are two supported ways of creating components:
53
+
54
+ * Path based components
55
+ * Name based components
56
+
57
+ #### Path based components
58
+
59
+ Path based components are components that infer their name based on
60
+ the base name of a file. These types of components use the `SparkleFormation.build`
61
+ method, which does not accept a name argument. For example:
62
+
63
+ ~~~ruby
64
+ # components/common.rb
65
+ SparkleFormation.build do
66
+ ...
67
+ end
68
+ ~~~
69
+
70
+ The name of this component will be `common`.
71
+
72
+ #### Name based components
73
+
74
+ Name based components are components whose names are explicitly
75
+ defined. These types of components use the `SparkleFormation.component`
76
+ method, which accepts a name argument. For example:
77
+
78
+ ~~~ruby
79
+ # components/my-common-component.rb
80
+ SparkleFormation.component(:core) do
81
+ ...
82
+ end
83
+ ~~~
84
+
85
+ The name of this component will be `core` as it is explicitly provided
86
+ when creating the component. These name based components are specifically
87
+ geared towards usage in "sparkle packs" or any other implementations where
88
+ a single file may provide multiple components or building blocks, or where
89
+ the file name may be required to be different from the name of the component.
90
+
91
+ ### Dynamics
92
+
93
+ Dynamics are reusable blocks of code that can be applied multiple times
94
+ within the same template to provide multiple discrete sets of content.
95
+ They provide the ability to refactor common template content out into
96
+ reusable and configurable dynamics that can then be re-inserted using
97
+ customized naming structures. Dynamics _always_ explicitly define their
98
+ name when creating unlike components which optionally supports explict
99
+ naming.
100
+
101
+ Dynamics are registered blocks which accept two parameters:
102
+
103
+ 1. Name for the dynamic call
104
+ 2. Configuration Hash for the dynamic call
105
+
106
+ Here is an example dynamic:
107
+
108
+ ~~~ruby
109
+ # dynamics/node.rb
110
+ SparkleFormation.dynamic(:node) do |_name, _config={}|
111
+ unless(_config[:ssh_key])
112
+ parameters.set!("#{_name}_ssh_key".to_sym) do
113
+ type 'String'
114
+ end
115
+ end
116
+ dynamic!(:ec2_instance, _name).properties do
117
+ key_name _config[:ssh_key] ? _config[:ssh_key] : ref!("#{_name}_ssh_key".to_sym)
118
+ end
119
+ end
120
+ ~~~
121
+
122
+ *NOTE: The underscore (`_`) prefix on the parameter names are simply a convention
123
+ and not required. It is a convention to make it easier to identify variables
124
+ used within the dynamic, and its usage is completely author dependent.*
125
+
126
+ The dynamic defines two parameters: `_name` and `_config`. The `_config`
127
+ parameter is defaulted to an empty Hash allowing the dynamic call to optionally
128
+ accept a configuration Hash. With this dynamic in place, it can be called
129
+ multiple times within a template:
130
+
131
+ ~~~ruby
132
+ SparkleFormation.new(:node_stack) do
133
+ dynamic!(:node, :fubar)
134
+ dynamic!(:node, :foobar, :ssh_key => 'default')
135
+ end
136
+ ~~~
137
+
138
+ #### Builtin Dynamics
139
+
140
+ SparkleFormation includes a lookup of known AWS resources which can be accessed
141
+ using the `dynamic!` method. This lookup is provided simply as a convenience
142
+ to speed development and compact implementations. When a builtin is inserted,
143
+ it will automatically set the `type` of the resource and evaluate an optionally
144
+ provided block within the resource. The following templates will generate
145
+ equivalent results when compiled:
146
+
147
+ ~~~ruby
148
+ SparkleFormation.new(:with_dynamic) do
149
+ dynamic!(:ec2_instance, :fubar).properties.key_name 'default'
150
+ end
151
+ ~~~
152
+
153
+ ~~~ruby
154
+ SparkleFormation.new(:without_dynamic) do
155
+ resources.fubar_ec2_instance do
156
+ type 'AWS::EC2::Instance'
157
+ properties.key_name 'default'
158
+ end
159
+ end
160
+ ~~~
161
+
162
+ ##### Builtin Lookup Behavior
163
+
164
+ Builtin lookups are based on the resource type. Resource matching is performed
165
+ using a *suffix based* match. When searching for matching types, the _first_
166
+ match is used. For example:
167
+
168
+ ~~~ruby
169
+ SparkleFormation.new(:class_only) do
170
+ dynamic!(:instance, :foobar)
171
+ end
172
+ ~~~
173
+
174
+ When the lookup is performed, this will match the `AWS::EC2::Instance` resource.
175
+ This may not be the correct match, however, since there is also an
176
+ `AWS::OpsWorks::Instance` resource type. The correct lookup can be forced (if
177
+ the `OpsWorks` resource is the desired resource) by providing the namespace
178
+ prefix:
179
+
180
+ ~~~ruby
181
+ SparkleFormation.new(:with_namespace) do
182
+ dynamic!(:opsworks_instance, :foobar)
183
+ end
184
+ ~~~
185
+
186
+ This can also be taken a step further by including the `AWS` namespace as well:
187
+
188
+ ~~~ruby
189
+ SparkleFormation.new(:with_namespace) do
190
+ dynamic!(:aws_opsworks_instance, :foobar)
191
+ end
192
+ ~~~
193
+
194
+ but will likely be a bit superfluous. It is also important to note the name
195
+ of the generated resource is dependent on the value of the first parameter.
196
+ The resultant resource names from the above three examples will be:
197
+
198
+ * FoobarInstance
199
+ * FoobarOpsworksInstance
200
+ * FoobarAwsOpsworksInstance
201
+
202
+ The value used for the suffix of the resource name can be provided with
203
+ the `dynamic!` call:
204
+
205
+ ~~~ruby
206
+ SparkleFormation.new(:with_namespace) do
207
+ dynamic!(:aws_opsworks_instance, :foobar,
208
+ :resource_suffix_name => :instance
209
+ )
210
+ end
211
+ ~~~
212
+
213
+ which will result in a resource name: `FoobarInstance`
214
+
215
+ ##### Dynamic Return Context
216
+
217
+ When defining custom dynamics, the result of the dynamic block is important.
218
+ A dynamic can make multiple modifications to a template when inserted. For
219
+ example, addition of parameters, resources, and/or outputs. It is important
220
+ to use the values returned from the dynamic block to prevent surprises.
221
+ When the `dynamic!` is called and provided a block, the block is evaluated
222
+ within the context returned from the `dynamic!`.
223
+
224
+ For example, this is an improper implementation of a dynamic:
225
+
226
+ ~~~ruby
227
+ SparkleFormation.dynamic(:bad_dynamic) do |_name, _config|
228
+ dynamic!(:ec2_instance, _name)
229
+ outputs do
230
+ address.value attr!("#{_name}_ec2_instance".to_sym, :public_ip)
231
+ end
232
+ end
233
+ ~~~
234
+
235
+ If a template attempts to use this dynamic and make an override modification
236
+ to the instance:
237
+
238
+ ~~~ruby
239
+ SparkleFormation.new(:failed_template) do
240
+ dynamic!(:bad_dynamic, :foobar) do
241
+ properties.key_name 'default'
242
+ end
243
+ end
244
+ ~~~
245
+
246
+ The `properties.key_name` will be evaluated within the context of the `outputs`
247
+ because it is the returned value of the dynamic block. Instead the dynamic should
248
+ return the context of the referenced resource (if applicable). To make the
249
+ dynamic act as expected, the resource must be returned from the block.
250
+
251
+ ~~~ruby
252
+ SparkleFormation.dynamic(:good_dynamic) do |_name, _config|
253
+ _resource = dynamic!(:ec2_instance, _name)
254
+ outputs do
255
+ address.value attr!("#{_name}_ec2_instance".to_sym, :public_ip)
256
+ end
257
+ _resource
258
+ end
259
+ ~~~
260
+
261
+ This will ensure the instance resource is the context returned. The blocks provided
262
+ will work as expected:
263
+
264
+ ~~~ruby
265
+ SparkleFormation.new(:successful_template) do
266
+ dynamic!(:good_dynamic, :foobar) do
267
+ properties.key_name 'default'
268
+ end
269
+ end
270
+ ~~~
271
+
272
+ ##### Dynamic Lookup Behavior
273
+
274
+ Dynamics can be loaded from multiple locations. When SparkleFormation performs
275
+ a dynamic lookup, the following locations are checked in order of precedence:
276
+
277
+ 1. Implementation local `dynamics` directory
278
+ 2. SparklePack dynamics with reverse load order precedence
279
+ 3. Builtin dynamics lookup table
280
+
281
+ ### Registry
282
+
283
+ Registry entries are lightweight dynamics that are useful for storing items that
284
+ may be used in multiple locations. For example, the valid sizes of an instance
285
+ within an infrastructure will generally be restricted to a specific list.
286
+ This list can be stored within a registry to provide a single point of
287
+ contact for any changes:
288
+
289
+ ~~~ruby
290
+ SfnRegistry.register(:instance_sizes) do
291
+ [
292
+ 'm3.large',
293
+ 'm3.medium',
294
+ 't2.medium'
295
+ ]
296
+ end
297
+ SfnRegistry.register(:instance_size_default){ 'm3.medium' }
298
+ ~~~
299
+
300
+ With the array registered as `registry!(:instance_sizes)`, we can now reference it:
301
+
302
+ ~~~ruby
303
+ SparkleFormation.new(:instance_stack) do
304
+ parameters.instance_size do
305
+ type 'String'
306
+ allowed_values registry!(:instance_sizes)
307
+ default registry!(:instance_size_default)
308
+ end
309
+ end
310
+ ~~~
311
+
312
+ ### Templates
313
+
314
+ Templates are the files that pull all the building blocks together to produce
315
+ a final data structure that will be serialized into a document. This data structure
316
+ can be submitted to an orchestration API.
317
+
318
+ There are three stages of template compilation:
319
+
320
+ 1. Evaluate optional block given on instantiation
321
+ 2. Evaluate any loaded components
322
+ 3. Evaluate `override` block
323
+
324
+ #### Instantiation Block
325
+
326
+ A block provided on instantiation is the first block evaluated:
327
+
328
+ ~~~ruby
329
+ SparkleFormation.new(:my_template) do
330
+ dynamic!(:ec2_instance, :foobar)
331
+ end
332
+ ~~~
333
+
334
+ #### Loaded Components
335
+
336
+ Components are evaluated in the order they are added to the template via
337
+ the `load` method:
338
+
339
+ ~~~ruby
340
+ SparkleFormation.new(:my_template) do
341
+ dynamic!(:ec2_instance, :foobar)
342
+ end.load(:common, :special)
343
+ ~~~
344
+
345
+ On compilation, this will evaluate the instantiation block first, the `common`
346
+ component second, and finally the `special` component.
347
+
348
+ #### Overrides
349
+
350
+ Override blocks are the final blocks evaluated during compilation:
351
+
352
+ ~~~ruby
353
+ SparkleFormation.new(:my_template) do
354
+ dynamic!(:ec2_instance, :foobar)
355
+ end.load(:common, :special).overrides do
356
+ resources.foobar_ec2_instance.properties.key_name 'default'
357
+ end
358
+ ~~~
359
+
360
+ [1]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself