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.
@@ -0,0 +1,303 @@
1
+ ---
2
+ title: "SparkleFormation DSL"
3
+ category: "dsl"
4
+ weight: 2
5
+ anchors:
6
+ - title: "Behavior"
7
+ url: "#behavior"
8
+ - title: "Key Alteration"
9
+ url: "#key-alteration"
10
+ - title: "Data Access"
11
+ url: "#data-access"
12
+ ---
13
+
14
+ ## SparkleFormation DSL
15
+
16
+ The SparkleFormation DSL (domain specific language) is based
17
+ on (and built on top of) the [AttributeStruct](https://github.com/chrisroberts/attribute_struct)
18
+ library. This provides SparkleFormation with its free-form behavior
19
+ and allows immediate support of any template style or API
20
+ updates requiring modifications to existing templates.
21
+
22
+ For a closer look at the underlying features provided by
23
+ the AttributeStruct library, please refer to the
24
+ [AttributeStruct documentation](https://chrisroberts.github.io/attribute_struct).
25
+
26
+ ### Behavior
27
+
28
+ The behavior of the SparkleFormation DSL is largely dictated by the
29
+ AttributeStruct library, and as such are not specific to SparkleFormation
30
+ alone. Some optional features of the AttributeStruct library are automatically
31
+ enabled when using SparkleFormation, most notably the automatic camel casing
32
+ of key values.
33
+
34
+ #### Key Alteration
35
+
36
+ The default behavior of SparkleFormation is to camel case all Hash keys.
37
+ This is done via:
38
+
39
+ ~~~ruby
40
+ AttributeStruct.camel_keys = true
41
+ ~~~
42
+
43
+ And results in all Hash keys in the resultant compile Hash being converted
44
+ to a camel cased format:
45
+
46
+ ~~~ruby
47
+ SparkleFormation.new(:test) do
48
+ parameters.creator.default 'spox'
49
+ end
50
+ ~~~
51
+
52
+ The resultant data structure after compiling:
53
+
54
+ ~~~ruby
55
+ {
56
+ "Parameters": {
57
+ "Creator": {
58
+ "Default": "spox"
59
+ }
60
+ }
61
+ }
62
+ ~~~
63
+
64
+ In some cases it may be desired to have a key _not_
65
+ be automatically camel cased. Camel casing can be
66
+ disabled via a helper method that is attached to the
67
+ Symbol and String instances:
68
+
69
+ ~~~ruby
70
+ SparkleFormation.new(:test) do
71
+ parameters.set!(:creator.disable_camel!).default 'spox'
72
+ end
73
+ ~~~
74
+
75
+ The resultant data structure after compiling:
76
+
77
+ ~~~ruby
78
+ {
79
+ "Parameters": {
80
+ "creator": {
81
+ "Default": "spox"
82
+ }
83
+ }
84
+ }
85
+ ~~~
86
+
87
+ Depending on the formatting of the target template there
88
+ may be lack of consistency within certain locations. A
89
+ classic example of this inconsistency can be seen in the
90
+ `AWS::CloudFormation::Init` metadata section on compute
91
+ type resources. Within the context of this `Init` section
92
+ the format of the keys change from the standard camel casing
93
+ to a snake cased format. It is possible to handle this by using
94
+ the `disable_camel!` method for all defined keys, but it is
95
+ clunky and reduces the readability of the code.
96
+
97
+ As the data structure is built when compiling the SparkleFormation
98
+ template state is tracked at each "level" of the data structure.
99
+ When the camel casing is enabled on AttributeStruct, this is merely
100
+ the default behavior and can be overridden, even from within
101
+ the DSL. For example:
102
+
103
+ ~~~ruby
104
+ SparkleFormation.new(:test) do
105
+ parameters do
106
+ camel_keys_set!(:auto_disable)
107
+ creator.default 'spox'
108
+ end
109
+ outputs.creator.value ref!(:creator.disable_camel!)
110
+ end
111
+ ~~~
112
+
113
+ The resultant data structure after compiling:
114
+
115
+ ~~~ruby
116
+ {
117
+ "Parameters": {
118
+ "creator": {
119
+ "default": "spox"
120
+ }
121
+ },
122
+ "Outputs": {
123
+ "Value": {
124
+ "Ref": "creator"
125
+ }
126
+ }
127
+ }
128
+ ~~~
129
+
130
+ This example shows how the behavior of the Hash key modification
131
+ can be altered at a specific context within the data structure.
132
+ New values added (as well as nested) will not the camel casing
133
+ modification applied. The behavior can be adjusted at multiple
134
+ depth locations, and that behavior will persist on re-entry:
135
+
136
+ ~~~ruby
137
+ SparkleFormation.new(:test) do
138
+ parameters do
139
+ camel_keys_set!(:auto_disable)
140
+ creator do
141
+ camel_keys_set!(:auto_enable)
142
+ default 'spox'
143
+ end
144
+ end
145
+ outputs.creator.value ref!(:creator.disable_camel!)
146
+ parameters.creator.type 'String'
147
+ parameters.author.default 'John Doe'
148
+ end
149
+ ~~~
150
+
151
+ The resultant data structure after compiling:
152
+
153
+ ~~~ruby
154
+ {
155
+ "Parameters": {
156
+ "creator": {
157
+ "Default": "spox",
158
+ "Type": "String"
159
+ },
160
+ "author": {
161
+ "default": "John Doe"
162
+ }
163
+ },
164
+ "Outputs": {
165
+ "Value": {
166
+ "Ref": "creator"
167
+ }
168
+ }
169
+ }
170
+ ~~~
171
+
172
+ ### Features
173
+
174
+ #### Data Access
175
+
176
+ As a SparkleFormation template is compiled it is dynamically
177
+ building the data structure defined by the template. Because
178
+ this data structure is being generated during compilation, the
179
+ template itself has access to this data and can inspect the
180
+ state of the data structure as it exists _at that specific
181
+ time_. This allows for inspecting previously defined data
182
+ and using that data for decision making, or to copy/modify into
183
+ other locations.
184
+
185
+ ##### Local Context Data
186
+
187
+ When using block style syntax in the DSL an optional parameter
188
+ can be defined for the block. If provided, AttributeStruct will
189
+ pass the local AttributeStruct instance to the block when it
190
+ is executed:
191
+
192
+ ~~~ruby
193
+ SparkleFormation.new(:test) do
194
+ parameters.creator.default 'spox'
195
+ parameters do |params|
196
+ author.default params.creator.default
197
+ end
198
+ end
199
+ ~~~
200
+
201
+ The resultant data structure after compiling:
202
+
203
+ ~~~ruby
204
+ {
205
+ "Parameters": {
206
+ "Creator": {
207
+ "Default": "spox"
208
+ },
209
+ "Author": {
210
+ "Default": "spox"
211
+ }
212
+ }
213
+ }
214
+ ~~~
215
+
216
+ ##### Parent Context Data
217
+
218
+ It is possible to access the parent context data from the current
219
+ context:
220
+
221
+ ~~~ruby
222
+ SparkleFormation.new(:test) do
223
+ parameters.creator.default 'spox'
224
+ parameters.author do
225
+ default parent!.creator.default
226
+ end
227
+ end
228
+ ~~~
229
+
230
+ The resultant data structure after compiling:
231
+
232
+ ~~~ruby
233
+ {
234
+ "Parameters": {
235
+ "Creator": {
236
+ "Default": "spox"
237
+ },
238
+ "Author": {
239
+ "Default": "spox"
240
+ }
241
+ }
242
+ }
243
+ ~~~
244
+
245
+
246
+ ##### Root Context Data
247
+
248
+ It is possible to access the root context data from the current
249
+ context:
250
+
251
+ ~~~ruby
252
+ SparkleFormation.new(:test) do
253
+ parameters.creator.default 'spox'
254
+ parameters.author.default root!.parameters.creator.default
255
+ end
256
+ ~~~
257
+
258
+ The resultant data structure after compiling:
259
+
260
+ ~~~ruby
261
+ {
262
+ "Parameters": {
263
+ "Creator": {
264
+ "Default": "spox"
265
+ },
266
+ "Author": {
267
+ "Default": "spox"
268
+ }
269
+ }
270
+ }
271
+ ~~~
272
+
273
+ ##### Raw Access
274
+
275
+ The raw Hash instance holding the data of the current context
276
+ can be reached using the `data!` method:
277
+
278
+ ~~~ruby
279
+ SparkleFormation.new(:test) do
280
+ parameters.creator.default 'spox'
281
+ if(data!['Creator'].default == 'spox')
282
+ parameters.author.default 'xops'
283
+ end
284
+ end
285
+ ~~~
286
+
287
+ The resultant data structure after compiling:
288
+
289
+ ~~~ruby
290
+ {
291
+ "Parameters": {
292
+ "Creator": {
293
+ "Default": "spox"
294
+ },
295
+ "Author": {
296
+ "Default": "xops"
297
+ }
298
+ }
299
+ }
300
+ ~~~
301
+
302
+ > NOTE: Because `data!` returns a Hash instance, no automatic formatting
303
+ > (camel case conversions) will be applied to keys when accessing values.
@@ -0,0 +1,90 @@
1
+ ---
2
+ title: "Stack Policies"
3
+ category: "dsl"
4
+ weight: 8
5
+ anchors:
6
+ - title: "Template Usage"
7
+ url: "#template-usage"
8
+ - title: "Library Usage"
9
+ url: "#library-usage"
10
+ ---
11
+
12
+ ## Stack Policies
13
+
14
+ AWS CloudFormation includes support for stack policies. These
15
+ policies add an extra layer of control that restricts or allows
16
+ actions to be taken on specific resources within a stack.
17
+ SparkleFormation includes support for extracting inline stack
18
+ policy information from SparkleFormation templates which can
19
+ then be applied to stacks.
20
+
21
+ * [AWS CFN Stack Policies](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html)
22
+
23
+ ### Template Usage
24
+
25
+ Resource policies can be defined within a SparkleFormation
26
+ template. This allows for policies to be programatically generated
27
+ in the same manner as the stack template itself.
28
+
29
+ ~~~ruby
30
+ template = SparkleFormation.new(:test) do
31
+ resources.my_resource do
32
+ policy do
33
+ allow 'Modify'
34
+ deny 'Replace'
35
+ end
36
+ end
37
+ end
38
+ ~~~
39
+
40
+ ### Library Usage
41
+
42
+ SparkleFormation can extract stack policies from a template after
43
+ it has been compiled. Once extracted, the policy can be applied
44
+ to the stack as dictated by the API.
45
+
46
+ ~~~ruby
47
+ template = SparkleFormation.new(:test) do
48
+ resources.my_resource do
49
+ policy do
50
+ allow 'Modify'
51
+ deny 'Replace'
52
+ end
53
+ end
54
+ end
55
+
56
+ policy = template.generate_policy
57
+ ~~~
58
+
59
+ This generates a policy data structure:
60
+
61
+ ~~~ruby
62
+ {
63
+ "Statement" => [
64
+ {
65
+ "Effect" => "Allow",
66
+ "Action" => [
67
+ "Update:*"
68
+ ],
69
+ "Resource" => "*",
70
+ "Principal" => "*"
71
+ },
72
+ {
73
+ "Effect" => "Allow",
74
+ "Action" => [
75
+ "Update:Modify"
76
+ ],
77
+ "Resource" => "LogicalResourceId/MyResource",
78
+ "Principal" => "*"
79
+ },
80
+ {
81
+ "Effect" => "Deny",
82
+ "Action" => [
83
+ "Update:Replace"
84
+ ],
85
+ "Resource" => "LogicalResourceId/MyResource",
86
+ "Principal" => "*"
87
+ }
88
+ ]
89
+ }
90
+ ~~~
@@ -0,0 +1,64 @@
1
+ ---
2
+ title: "Translation"
3
+ category: "dsl"
4
+ weight: 9
5
+ anchors:
6
+ - title: "Supported Translations"
7
+ url: "#supported-translations"
8
+ - title: "Usage"
9
+ url: "#usage"
10
+ ---
11
+
12
+ ## Translation
13
+
14
+ SparkleFormation has alpha support for template translation from
15
+ AWS CFN to target orchestration API template formats.
16
+
17
+ > NOTE: Translations do not currently support stack nesting functionality
18
+
19
+ ### Supported Translations
20
+
21
+ Basic support implementations:
22
+
23
+ * OpenStack
24
+ * Rackspace
25
+
26
+ ### Usage
27
+
28
+ Translations are based around AWS CFN and then target some
29
+ remote orchestration API (currently Heat and Rackspace). First
30
+ the template must be compiled, then it is passed to the translator
31
+ which converts the CFN specific template to the expected format
32
+ of the target API:
33
+
34
+ ~~~ruby
35
+ sfn = SparkleFormation.new(:my_stack) do
36
+ ...
37
+ end
38
+
39
+ cfn_template = sfn.compile.dump!
40
+ translator = SparkleFormation::Translation::Heat.new(cfn_template)
41
+
42
+ heat_template = translator.translate!
43
+ ~~~
44
+
45
+ In general applications of translators, the implementation will
46
+ first collect optional template parameters prior to translation
47
+ allowing the translator access to parameters that may be required
48
+ in places where the resultant template may not have support for
49
+ dynamic references. These can then be passed to the translator:
50
+
51
+ ~~~ruby
52
+ sfn = SparkleFormation.new(:my_stack) do
53
+ ...
54
+ end
55
+
56
+ cfn_template = sfn.compile.dump!
57
+ custom_params = collect_parameters(cfn_template)
58
+ translator = SparkleFormation::Translation::Heat.new(
59
+ cfn_template,
60
+ :parameters => custom_params
61
+ )
62
+
63
+ heat_template = translator.translate!
64
+ ~~~