sparkle_formation 0.2.4 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|