sparkle_formation 0.2.4 → 0.2.6
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +8 -9
- data/bin/generate_sparkle_docs +14 -8
- data/lib/sparkle_formation/sparkle_attribute.rb +19 -1
- data/lib/sparkle_formation/sparkle_formation.rb +155 -8
- data/lib/sparkle_formation/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 629f237b850e9be0623bc58499ee7576018730a4
|
4
|
+
data.tar.gz: 9b602ddb998707e16a1c45ff08e12b5a175a485c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d527b10cca86fb282187e4e9c6672dd89957b00b8ffa6b8c7ace56b6ab3c67e639f425a89cd9091798c0073d9a1495ed4d75b17bed50026ec78c2f9298df14ae
|
7
|
+
data.tar.gz: d4c775dcd1114e10d3c707ce863c836125ee035bc4bfbd2122261340c330844fec335ba6ca8b28b7e497b25ae914d2bb7e7b0f4b298c6a771b2130d250f90c28
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -32,14 +32,13 @@ SparkleFormation.new('ec2_example') do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
mappings.region_map do
|
35
|
-
set!('us-east-1', :ami => 'ami-7f418316')
|
36
|
-
set!('us-
|
37
|
-
set!('us-west-
|
38
|
-
set!('
|
39
|
-
set!('
|
40
|
-
set!('
|
41
|
-
set!('ap-
|
42
|
-
set!('ap-northeast-1', :ami => 'ami-dcfa4edd')
|
35
|
+
set!('us-east-1'._no_hump, :ami => 'ami-7f418316')
|
36
|
+
set!('us-west-1'._no_hump, :ami => 'ami-951945d0')
|
37
|
+
set!('us-west-2'._no_hump, :ami => 'ami-16fd7026')
|
38
|
+
set!('eu-west-1'._no_hump, :ami => 'ami-24506250')
|
39
|
+
set!('sa-east-1'._no_hump, :ami => 'ami-3e3be423')
|
40
|
+
set!('ap-southeast-1'._no_hump, :ami => 'ami-74dda626')
|
41
|
+
set!('ap-northeast-1'._no_hump, :ami => 'ami-dcfa4edd')
|
43
42
|
end
|
44
43
|
|
45
44
|
dynamic!(:ec2_instance, :foobar) do
|
@@ -109,7 +108,7 @@ templates.
|
|
109
108
|
First, create the component (components/ami.rb):
|
110
109
|
|
111
110
|
```ruby
|
112
|
-
SparkleFormation.build
|
111
|
+
SparkleFormation.build do
|
113
112
|
|
114
113
|
mappings.region_map do
|
115
114
|
set!('us-east-1', :ami => 'ami-7f418316')
|
data/bin/generate_sparkle_docs
CHANGED
@@ -11,15 +11,21 @@ FileUtils.mkdir_p('doc/UserDocs')
|
|
11
11
|
Dir.glob('docs/**/*').each do |path|
|
12
12
|
next unless File.file?(path)
|
13
13
|
content = File.read(path)
|
14
|
-
|
14
|
+
rel_path = path.sub(/.*?docs\//, '')
|
15
|
+
new_path = File.join('doc/UserDocs', rel_path)
|
16
|
+
user_doc_root = (['..'] * rel_path.scan('/').size).join('/')
|
17
|
+
unless(user_doc_root.to_s.empty?)
|
18
|
+
user_doc_root << '/'
|
19
|
+
end
|
15
20
|
FileUtils.mkdir_p(File.dirname(new_path))
|
16
|
-
File.open(new_path
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
file.
|
21
|
+
File.open(new_path, 'w') do |file|
|
22
|
+
file.puts content
|
23
|
+
end
|
24
|
+
if(new_path.end_with?('.md'))
|
25
|
+
File.open(new_path.sub('.md', '.html'), 'w') do |file|
|
26
|
+
file.print "<!DOCTYPE html><html><head><title>SparkleFormation User Documentation</title><script src=\"#{user_doc_root}v/0.3.2/marked.js\"></script><script src=\"#{user_doc_root}v/jquery-2.1.3.min.js\"></script><script src=\"#{user_doc_root}v/loader.js\"></script><script src=\"#{user_doc_root}v/highlight.min.js\"></script><link rel=\"stylesheet\" href=\"#{user_doc_root}v/bootstrap.min.css\"></link><link rel=\"stylesheet\" href=\"#{user_doc_root}v/highlight.min.css\"></link><link rel=\"stylesheet\" href=\"#{user_doc_root}v/finalizer.css\"></link>"
|
27
|
+
file.print "</head><body><div class=\"markdown-body\"><div class=\"navbar navbar-top\"><div class=\"navbar-inner\"><div class=\"container\"><div class=\"navbar-brand\"><a href=\"#{user_doc_root}README.html\">SparkleFormation - User documentation</a></div></div></div></div><div class=\"panel panel-default\"><div class=\"panel-body\" id=\"content\"></div></div></div>"
|
28
|
+
file.print "</body></html>"
|
23
29
|
end
|
24
30
|
end
|
25
31
|
end
|
@@ -170,7 +170,7 @@ class SparkleFormation
|
|
170
170
|
def _and(*args)
|
171
171
|
{
|
172
172
|
'Fn::And' => _array(
|
173
|
-
args.map{|v|
|
173
|
+
*args.map{|v|
|
174
174
|
if(v.is_a?(Symbol) || v.is_a?(String))
|
175
175
|
_condition(v)
|
176
176
|
else
|
@@ -226,6 +226,15 @@ class SparkleFormation
|
|
226
226
|
end
|
227
227
|
alias_method :or!, :_or
|
228
228
|
|
229
|
+
# Execute system command
|
230
|
+
#
|
231
|
+
# @param command [String]
|
232
|
+
# @return [String] result
|
233
|
+
def _system(command)
|
234
|
+
::Kernel.send('`', command)
|
235
|
+
end
|
236
|
+
alias_method :system!, :_system
|
237
|
+
|
229
238
|
# @return [TrueClass, FalseClass]
|
230
239
|
def rhel?
|
231
240
|
!!@platform[:rhel]
|
@@ -264,5 +273,14 @@ class SparkleFormation
|
|
264
273
|
SfnRegistry.insert(name, self, *args)
|
265
274
|
end
|
266
275
|
|
276
|
+
# Stack nesting helper method
|
277
|
+
#
|
278
|
+
# @param template [String, Symbol] template to nest
|
279
|
+
# @param args [String, Symbol] stringified and underscore joined for name
|
280
|
+
# @return [self]
|
281
|
+
def nest!(template, *args, &block)
|
282
|
+
SparkleFormation.nest(template, self, *args, &block)
|
283
|
+
end
|
284
|
+
|
267
285
|
end
|
268
286
|
end
|
@@ -28,6 +28,13 @@ class SparkleFormation
|
|
28
28
|
extend SparkleFormation::Utils::AnimalStrings
|
29
29
|
# @!parse extend SparkleFormation::Utils::AnimalStrings
|
30
30
|
|
31
|
+
# @return [Array<String>] directory names to ignore
|
32
|
+
IGNORE_DIRECTORIES = [
|
33
|
+
'components',
|
34
|
+
'dynamics',
|
35
|
+
'registry'
|
36
|
+
]
|
37
|
+
|
31
38
|
class << self
|
32
39
|
|
33
40
|
# @return [Hashish] loaded dynamics
|
@@ -204,6 +211,36 @@ class SparkleFormation
|
|
204
211
|
result
|
205
212
|
end
|
206
213
|
|
214
|
+
# Nest a template into a context
|
215
|
+
#
|
216
|
+
# @param template [String, Symbol] template to nest
|
217
|
+
# @param struct [SparkleStruct] context for nesting
|
218
|
+
# @param args [String, Symbol] stringified and underscore joined for name
|
219
|
+
# @return [SparkleStruct]
|
220
|
+
# @note if symbol is provided for template, double underscores
|
221
|
+
# will be used for directory separator and dashes will match underscores
|
222
|
+
def nest(template, struct, *args, &block)
|
223
|
+
spath = SparkleFormation.new('stub').sparkle_path
|
224
|
+
resource_name = [template.to_s.gsub(/(\/|__|-)/, '_'), *args].compact.join('_').to_sym
|
225
|
+
path = template.is_a?(Symbol) ? template.to_s.gsub('__', '/') : template.to_s
|
226
|
+
file = Dir.glob(File.join(spath, '**', '**', '*.rb')).detect do |local_path|
|
227
|
+
strip_path = local_path.sub(spath, '').sub(/^\//, '').tr('-', '_').sub('.rb', '')
|
228
|
+
strip_path == path
|
229
|
+
end
|
230
|
+
unless(file)
|
231
|
+
raise ArgumentError.new("Failed to locate nested stack file! (#{template.inspect} -> #{path.inspect})")
|
232
|
+
end
|
233
|
+
instance = self.instance_eval(IO.read(file), file, 1)
|
234
|
+
struct.resources.set!(resource_name) do
|
235
|
+
type 'AWS::CloudFormation::Stack'
|
236
|
+
end
|
237
|
+
struct.resources.__send__(resource_name).properties.stack instance.compile
|
238
|
+
if(block_given?)
|
239
|
+
struct.resources.__send__(resource_name).instance_exec(&block)
|
240
|
+
end
|
241
|
+
struct.resources.__send__(resource_name)
|
242
|
+
end
|
243
|
+
|
207
244
|
# Insert a builtin dynamic into a context
|
208
245
|
#
|
209
246
|
# @param dynamic_name [String, Symbol] dynamic name
|
@@ -300,6 +337,7 @@ class SparkleFormation
|
|
300
337
|
if(block)
|
301
338
|
load_block(block)
|
302
339
|
end
|
340
|
+
@compiled = nil
|
303
341
|
end
|
304
342
|
|
305
343
|
# Add block to load order
|
@@ -344,17 +382,126 @@ class SparkleFormation
|
|
344
382
|
#
|
345
383
|
# @return [SparkleStruct]
|
346
384
|
def compile
|
347
|
-
compiled
|
348
|
-
|
349
|
-
|
385
|
+
unless(@compiled)
|
386
|
+
compiled = SparkleStruct.new
|
387
|
+
@load_order.each do |key|
|
388
|
+
compiled._merge!(components[key])
|
389
|
+
end
|
390
|
+
@overrides.each do |override|
|
391
|
+
if(override[:args] && !override[:args].empty?)
|
392
|
+
compiled._set_state(override[:args])
|
393
|
+
end
|
394
|
+
self.class.build(compiled, &override[:block])
|
395
|
+
end
|
396
|
+
@compiled = compiled
|
397
|
+
end
|
398
|
+
@compiled
|
399
|
+
end
|
400
|
+
|
401
|
+
# Clear compiled stack if cached and perform compilation again
|
402
|
+
#
|
403
|
+
# @return [SparkleStruct]
|
404
|
+
def recompile
|
405
|
+
@compiled = nil
|
406
|
+
compile
|
407
|
+
end
|
408
|
+
|
409
|
+
# @return [TrueClass, FalseClass] includes nested stacks
|
410
|
+
def nested?
|
411
|
+
!!compile.dump!['Resources'].detect do |r_name, resource|
|
412
|
+
resource['Type'] == 'AWS::CloudFormation::Stack'
|
350
413
|
end
|
351
|
-
|
352
|
-
|
353
|
-
|
414
|
+
end
|
415
|
+
|
416
|
+
# @return [TrueClass, FalseClass] includes _only_ nested stacks
|
417
|
+
def isolated_nests?
|
418
|
+
hash = compile.dump!
|
419
|
+
(hash.keys == ['Resources'] || hash.keys == ['Resources', 'AWSTemplateFormatVersion']) &&
|
420
|
+
!hash['Resources'].detect{|_, r| r['Type'] != 'AWS::CloudFormation::Stack'}
|
421
|
+
end
|
422
|
+
|
423
|
+
# Apply stack nesting logic. Will extract unique parameters from
|
424
|
+
# nested stacks, update refs to use sibling stack outputs where
|
425
|
+
# required and extract nested stack templates for remote persistence
|
426
|
+
#
|
427
|
+
# @yieldparam template_name [String] nested stack resource name
|
428
|
+
# @yieldparam template [Hash] nested stack template
|
429
|
+
# @yieldreturn [String] remote URL
|
430
|
+
# @return [Hash] dumped template hash
|
431
|
+
def apply_nesting
|
432
|
+
hash = compile.dump!
|
433
|
+
stacks = Hash[
|
434
|
+
hash['Resources'].find_all do |r_name, resource|
|
435
|
+
[r_name, MultiJson.load(MultiJson.dump(resource))]
|
436
|
+
end
|
437
|
+
]
|
438
|
+
parameters = hash.fetch('Parameters', {})
|
439
|
+
output_map = {}
|
440
|
+
stacks.each do |stack_name, stack_resource|
|
441
|
+
remap_nested_parameters(hash, parameters, stack_name, stack_resource, output_map)
|
442
|
+
end
|
443
|
+
hash['Parameters'] = parameters
|
444
|
+
hash['Resources'].each do |resource_name, resource|
|
445
|
+
if(resource['Type'] == 'AWS::CloudFormation::Stack')
|
446
|
+
stack = resource['Properties'].delete('Stack')
|
447
|
+
resource['Properties']['TemplateURL'] = yield(resource_name, stack)
|
354
448
|
end
|
355
|
-
self.class.build(compiled, &override[:block])
|
356
449
|
end
|
357
|
-
|
450
|
+
hash
|
451
|
+
end
|
452
|
+
|
453
|
+
# Extract parameters from nested stacks. Check for previous nested
|
454
|
+
# stack outputs that match parameter. If match, set parameter to use
|
455
|
+
# output. If no match, check container stack parameters for match.
|
456
|
+
# If match, set to use ref. If no match, add parameter to container
|
457
|
+
# stack parameters and set to use ref.
|
458
|
+
#
|
459
|
+
# @param template [Hash] template being processed
|
460
|
+
# @param parameters [Hash] top level parameter set being built
|
461
|
+
# @param stack_name [String] name of stack resource
|
462
|
+
# @param stack_resource [Hash] duplicate of stack resource contents
|
463
|
+
# @param output_map [Hash] mapping of output names to required stack output access
|
464
|
+
# @return [TrueClass]
|
465
|
+
# @note if parameter has includes `StackUnique` a new parameter will
|
466
|
+
# be added to container stack and it will not use outputs
|
467
|
+
def remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map)
|
468
|
+
stack_parameters = stack_resource['Properties']['Stack']['Parameters']
|
469
|
+
if(stack_parameters)
|
470
|
+
template['Resources'][stack_name]['Properties']['Parameters'] ||= {}
|
471
|
+
stack_parameters.each do |pname, pval|
|
472
|
+
if(pval['StackUnique'])
|
473
|
+
check_name = [stack_name, pname].join
|
474
|
+
else
|
475
|
+
check_name = pname
|
476
|
+
end
|
477
|
+
if(parameters.keys.include?(check_name))
|
478
|
+
if(parameters[check_name]['Type'] == 'CommaDelimitedList')
|
479
|
+
new_val = {'Fn::Join' => [',', {'Ref' => check_name}]}
|
480
|
+
else
|
481
|
+
new_val = {'Ref' => check_name}
|
482
|
+
end
|
483
|
+
template['Resources'][stack_name]['Properties']['Parameters'][pname] = new_val
|
484
|
+
elsif(output_map[check_name])
|
485
|
+
template['Resources'][stack_name]['Properties']['Parameters'][pname] = {
|
486
|
+
'Fn::GetAtt' => output_map[check_name]
|
487
|
+
}
|
488
|
+
else
|
489
|
+
if(pval['Type'] == 'CommaDelimitedList')
|
490
|
+
new_val = {'Fn::Join' => [',', {'Ref' => check_name}]}
|
491
|
+
else
|
492
|
+
new_val = {'Ref' => check_name}
|
493
|
+
end
|
494
|
+
template['Resources'][stack_name]['Properties']['Parameters'][pname] = new_val
|
495
|
+
parameters[check_name] = pval
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
if(stack_resource['Properties']['Stack']['Outputs'])
|
500
|
+
stack_resource['Properties']['Stack']['Outputs'].keys.each do |oname|
|
501
|
+
output_map[oname] = [stack_name, "Outputs.#{oname}"]
|
502
|
+
end
|
503
|
+
end
|
504
|
+
true
|
358
505
|
end
|
359
506
|
|
360
507
|
# @return [Hash] dumped hash
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sparkle_formation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attribute_struct
|