sparkle_formation 1.0.4 → 1.1.0

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 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