sparkle_formation 1.2.0 → 2.0.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,21 @@
1
+ require 'sparkle_formation'
2
+
3
+ class SparkleFormation
4
+
5
+ # Provides template helper methods
6
+ module SparkleAttribute
7
+
8
+ # Rackspace specific helper implementations
9
+ module Rackspace
10
+
11
+ # @!parse include SparkleFormation::SparkleAttribute::Heat
12
+
13
+ # Set customized struct behavior
14
+ def self.included(klass)
15
+ klass.include SparkleFormation::SparkleAttribute::Heat
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
@@ -224,7 +224,7 @@ class SparkleFormation
224
224
  unless(result)
225
225
  message = "Failed to locate requested dynamic block for insertion: #{dynamic_name} " \
226
226
  "(valid: #{struct._self.sparkle.dynamics.keys.sort.join(', ')})"
227
- if(struct._self.provider_resources.registry.keys.size > 1)
227
+ if(struct._self.provider_resources && struct._self.provider_resources.registry.keys.size > 1)
228
228
  t_name = struct._self.provider_resources.registry.keys.first
229
229
  message << "\nBuiltin dynamics pattern `#{t_name}` -> `:#{Bogo::Utility.snake(t_name.gsub('::', '_'))}`"
230
230
  end
@@ -266,7 +266,14 @@ class SparkleFormation
266
266
  nested_template.compile_state = options[:parameters]
267
267
  end
268
268
  struct.resources.set!(resource_name) do
269
- type DEFAULT_STACK_RESOURCE
269
+ type struct._self.stack_resource_type
270
+ end
271
+ unless(struct._self.sparkle.empty?)
272
+ struct._self.sparkle.size.times do |idx|
273
+ nested_template.sparkle.add_sparkle(
274
+ struct._self.sparkle.sparkle_at(idx)
275
+ )
276
+ end
270
277
  end
271
278
  struct.resources[resource_name].properties.stack nested_template
272
279
  if(block_given?)
@@ -380,7 +387,8 @@ class SparkleFormation
380
387
  }
381
388
  )
382
389
  )
383
- unless(options[:disable_aws_builtins])
390
+ self.provider = options.fetch(:provider, @parent ? @parent.provider : :aws)
391
+ if(provider == :aws || !options[:disable_aws_builtins])
384
392
  require 'sparkle_formation/aws'
385
393
  end
386
394
  @parameters = set_generation_parameters!(
@@ -388,21 +396,25 @@ class SparkleFormation
388
396
  options.fetch(:parameters, {})
389
397
  )
390
398
  )
391
- @stack_resource_types = (
392
- VALID_STACK_RESOURCES +
393
- options.fetch(:stack_resource_types, [])
394
- ).uniq
399
+ @stack_resource_types = [
400
+ stack_resource_type,
401
+ *options.fetch(:stack_resource_types, [])
402
+ ].compact.uniq
395
403
  @components = Smash.new
396
404
  @load_order = []
397
405
  @overrides = []
398
406
  @parent = options[:parent]
399
- @provider = options.fetch(:provider, @parent ? @parent.provider : :aws)
400
407
  if(block)
401
408
  load_block(block)
402
409
  end
403
410
  @compiled = nil
404
411
  end
405
412
 
413
+ # @return [String] provider stack resource type
414
+ def stack_resource_type
415
+ DEFAULT_STACK_RESOURCE
416
+ end
417
+
406
418
  # Set remote API target for template to allow loading of
407
419
  # provider specific helpers and data if available. Setting
408
420
  # to a false-y value will disable helpers loading
@@ -412,6 +424,11 @@ class SparkleFormation
412
424
  def provider=(val)
413
425
  if(val)
414
426
  @provider = Bogo::Utility.snake(val).to_sym
427
+ provider_klass = Bogo::Utility.camel(@provider.to_s)
428
+ if(Provider.const_defined?(provider_klass))
429
+ extend Provider.const_get(provider_klass)
430
+ end
431
+ @provider
415
432
  else
416
433
  @provider = nil
417
434
  end
@@ -558,6 +575,12 @@ class SparkleFormation
558
575
  compiled = struct_class.new
559
576
  compiled._set_self(self)
560
577
  compiled._struct_class = struct_class
578
+ if(struct_class.const_defined?(:CAMEL_KEYS))
579
+ compiled._camel_keys = struct_class.const_get(:CAMEL_KEYS)
580
+ end
581
+ if(struct_class.const_defined?(:CAMEL_STYLE))
582
+ compiled._camel_style = struct_class.const_get(:CAMEL_STYLE)
583
+ end
561
584
  if(compile_state)
562
585
  compiled.set_state!(compile_state)
563
586
  end
@@ -587,71 +610,65 @@ class SparkleFormation
587
610
 
588
611
  # @return [Array<SparkleFormation>]
589
612
  def nested_stacks(*args)
590
- compile.resources.keys!.map do |key|
591
- if(stack_resource_type?(compile.resources[key].type))
592
- result = [compile.resources[key].properties.stack]
593
- if(args.include?(:with_resource))
594
- result.push(compile[:resources][key])
595
- end
596
- if(args.include?(:with_name))
597
- result.push(key)
613
+ if(compile[:resources])
614
+ compile.resources.keys!.map do |key|
615
+ if(stack_resource_type?(compile.resources[key].type))
616
+ result = [compile.resources[key].properties.stack]
617
+ if(args.include?(:with_resource))
618
+ result.push(compile[:resources][key])
619
+ end
620
+ if(args.include?(:with_name))
621
+ result.push(key)
622
+ end
623
+ result.size == 1 ? result.first : result
598
624
  end
599
- result.size == 1 ? result.first : result
600
- end
601
- end.compact
625
+ end.compact
626
+ else
627
+ []
628
+ end
602
629
  end
603
630
 
604
631
  # @return [TrueClass, FalseClass] includes nested stacks
605
632
  def nested?(stack_hash=nil)
606
- stack_hash = compile.dump! unless stack_hash
607
- !!stack_hash.fetch('Resources', {}).detect do |_r_name, resource|
608
- stack_resource_type?(resource['Type'])
633
+ if(stack_hash)
634
+ raise Error::Deprecated.new "Hash parameter no longer valid for this method (`#{self.class}##{__callee__}`)"
635
+ end
636
+ unless(compile.resources.nil?)
637
+ compile.resources._data.any? do |r_name, r_value|
638
+ stack_resource_type?(r_value.type)
639
+ end
609
640
  end
610
641
  end
611
642
 
612
643
  # @return [TrueClass, FalseClass] includes _only_ nested stacks
613
644
  def isolated_nests?(stack_hash=nil)
614
- stack_hash = compile.dump! unless stack_hash
615
- stack_hash.fetch('Resources', {}).all? do |_name, resource|
616
- stack_resource_type?(resource['Type'])
645
+ if(stack_hash)
646
+ raise Error::Deprecated.new "Hash parameter no longer valid for this method (`#{self.class}##{__callee__}`)"
647
+ end
648
+ unless(compile.resources.nil?)
649
+ compile.resources._data.all? do |r_name, r_value|
650
+ stack_resource_type?(r_value.type)
651
+ end
617
652
  end
618
653
  end
619
654
 
620
655
  # @return [TrueClass, FalseClass] policies defined
621
656
  def includes_policies?(stack_hash=nil)
622
- stack_hash = compile.dump! unless stack_hash
623
- stack_hash.fetch('Resources', {}).any? do |_name, resource|
624
- resource.key?('Policy')
657
+ if(stack_hash)
658
+ raise Error::Deprecated.new "Hash parameter no longer valid for this method (`#{self.class}##{__callee__}`)"
659
+ end
660
+ unless(compile.resources.nil?)
661
+ compile.resources._data.any? do |r_name, r_value|
662
+ !r_value.policy.nil?
663
+ end
625
664
  end
626
665
  end
627
666
 
628
667
  # Generate policy for stack
629
668
  #
630
669
  # @return [Hash]
631
- # @todo this is very AWS specific, so make this easy for swapping
632
670
  def generate_policy
633
- statements = []
634
- compile.resources.keys!.each do |r_name|
635
- r_object = compile.resources[r_name]
636
- if(r_object['Policy'])
637
- r_object['Policy'].keys!.each do |effect|
638
- statements.push(
639
- 'Effect' => effect.to_s.capitalize,
640
- 'Action' => [r_object['Policy'][effect]].flatten.compact.map{|i| "Update:#{i}"},
641
- 'Resource' => "LogicalResourceId/#{r_name}",
642
- 'Principal' => '*'
643
- )
644
- end
645
- r_object.delete!('Policy')
646
- end
647
- end
648
- statements.push(
649
- 'Effect' => 'Allow',
650
- 'Action' => 'Update:*',
651
- 'Resource' => '*',
652
- 'Principal' => '*'
653
- )
654
- Smash.new('Statement' => statements)
671
+ Smash.new
655
672
  end
656
673
 
657
674
  # Apply nesting logic to stack
@@ -678,22 +695,6 @@ class SparkleFormation
678
695
  # @yieldreturn [Hash] key/values to be merged into resource properties
679
696
  # @return [Hash] dumped stack
680
697
  def apply_deep_nesting(*args, &block)
681
- outputs = collect_outputs
682
- nested_stacks(:with_resource).each do |stack, resource|
683
- unless(stack.nested_stacks.empty?)
684
- stack.apply_deep_nesting(*args)
685
- end
686
- stack.compile.parameters.keys!.each do |parameter_name|
687
- if(output_name = output_matched?(parameter_name, outputs.keys))
688
- next if outputs[output_name] == stack
689
- stack_output = stack.make_output_available(output_name, outputs)
690
- resource.properties.parameters.set!(parameter_name, stack_output)
691
- end
692
- end
693
- end
694
- if(block_given?)
695
- extract_templates(&block)
696
- end
697
698
  compile.dump!
698
699
  end
699
700
 
@@ -716,40 +717,7 @@ class SparkleFormation
716
717
  # @param outputs [Hash] listing of outputs
717
718
  # @reutrn [Hash] reference to output value (used for setting parameter)
718
719
  def make_output_available(output_name, outputs)
719
- bubble_path = outputs[output_name].root_path - root_path
720
- drip_path = root_path - outputs[output_name].root_path
721
- bubble_path.each_slice(2) do |base_sparkle, ref_sparkle|
722
- next unless ref_sparkle
723
- base_sparkle.compile.outputs.set!(output_name).set!(
724
- :value, base_sparkle.compile.attr!(
725
- ref_sparkle.name, "Outputs.#{output_name}"
726
- )
727
- )
728
- end
729
- if(bubble_path.empty?)
730
- if(drip_path.size == 1)
731
- parent = drip_path.first.parent
732
- if(parent && parent.compile.parameters.data![output_name])
733
- return compile.ref!(output_name)
734
- end
735
- end
736
- raise ArgumentError.new "Failed to detect available bubbling path for output `#{output_name}`. " <<
737
- 'This may be due to a circular dependency! ' <<
738
- "(Output Path: #{outputs[output_name].root_path.map(&:name).join(' > ')} " <<
739
- "Requester Path: #{root_path.map(&:name).join(' > ')})"
740
- end
741
- result = compile.attr!(bubble_path.first.name, "Outputs.#{output_name}")
742
- if(drip_path.size > 1)
743
- parent = drip_path.first.parent
744
- drip_path.unshift(parent) if parent
745
- drip_path.each_slice(2) do |base_sparkle, ref_sparkle|
746
- next unless ref_sparkle
747
- base_sparkle.compile.resources[ref_sparkle.name].properties.parameters.set!(output_name, result)
748
- ref_sparkle.compile.parameters.set!(output_name){ type 'String' } # TODO: <<<<------ type check and prop
749
- result = compile.ref!(output_name)
750
- end
751
- end
752
- result
720
+ {}
753
721
  end
754
722
 
755
723
  # Extract and process nested stacks
@@ -785,32 +753,13 @@ class SparkleFormation
785
753
  # @yieldreturn [String] Remote URL storage for template
786
754
  # @return [Hash]
787
755
  def apply_shallow_nesting(*args, &block)
788
- parameters = compile[:parameters] ? compile[:parameters]._dump : {}
789
- output_map = {}
790
- nested_stacks(:with_resource, :with_name).each do |_stack, stack_resource, stack_name|
791
- remap_nested_parameters(compile, parameters, stack_name, stack_resource, output_map)
792
- end
793
- extract_templates(&block)
794
- compile.parameters parameters
795
- if(args.include?(:bubble_outputs))
796
- outputs_hash = Hash[
797
- output_map do |name, value|
798
- [name, {'Value' => {'Fn::GetAtt' => value}}]
799
- end
800
- ]
801
- if(compile.outputs)
802
- compile._merge(compile._klass_new(outputs_hash))
803
- else
804
- compile.outputs output_hash
805
- end
806
- end
807
756
  compile.dump!
808
757
  end
809
758
 
810
759
  # @return [Smash<output_name:SparkleFormation>]
811
760
  def collect_outputs(*args)
812
761
  if(args.include?(:force) || root?)
813
- if(compile.outputs)
762
+ unless(compile.outputs.nil?)
814
763
  outputs = Smash[
815
764
  compile.outputs.keys!.zip(
816
765
  [self] * compile.outputs.keys!.size
@@ -843,39 +792,6 @@ class SparkleFormation
843
792
  # @note if parameter has includes `StackUnique` a new parameter will
844
793
  # be added to container stack and it will not use outputs
845
794
  def remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map)
846
- stack_parameters = stack_resource.properties.stack.compile.parameters
847
- unless(stack_parameters.nil?)
848
- stack_parameters._dump.each do |pname, pval|
849
- if(pval['StackUnique'])
850
- check_name = [stack_name, pname].join
851
- else
852
- check_name = pname
853
- end
854
- if(parameters.keys.include?(check_name))
855
- if(parameters[check_name]['Type'] == 'CommaDelimitedList')
856
- new_val = {'Fn::Join' => [',', {'Ref' => check_name}]}
857
- else
858
- new_val = {'Ref' => check_name}
859
- end
860
- template.resources.set!(stack_name).properties.parameters.set!(pname, new_val)
861
- elsif(output_map[check_name])
862
- template.resources.set!(stack_name).properties.parameters.set!(pname, 'Fn::GetAtt' => output_map[check_name])
863
- else
864
- if(pval['Type'] == 'CommaDelimitedList')
865
- new_val = {'Fn::Join' => [',', {'Ref' => check_name}]}
866
- else
867
- new_val = {'Ref' => check_name}
868
- end
869
- template.resources.set!(stack_name).properties.parameters.set!(pname, new_val)
870
- parameters[check_name] = pval
871
- end
872
- end
873
- end
874
- unless(stack_resource.properties.stack.compile.outputs.nil?)
875
- stack_resource.properties.stack.compile.outputs.keys!.each do |oname|
876
- output_map[oname] = [stack_name, "Outputs.#{oname}"]
877
- end
878
- end
879
795
  true
880
796
  end
881
797
 
@@ -45,6 +45,40 @@ class SparkleFormation
45
45
  end
46
46
  end
47
47
 
48
+ # Process value in search for FunctionStruct objects. If found replace with
49
+ # the root item of the structure
50
+ #
51
+ # @param item [Object]
52
+ # @return [Object]
53
+ def function_bubbler(item)
54
+ if(item.is_a?(::Enumerable))
55
+ if(item.respond_to?(:keys))
56
+ item.class[
57
+ *item.map do |entry|
58
+ function_bubbler(entry)
59
+ end.flatten(1)
60
+ ]
61
+ else
62
+ item.class[
63
+ *item.map do |entry|
64
+ function_bubbler(entry)
65
+ end
66
+ ]
67
+ end
68
+ elsif(item.is_a?(::SparkleFormation::FunctionStruct))
69
+ item._root
70
+ else
71
+ item
72
+ end
73
+ end
74
+
75
+ # Override to inspect result value and fetch root if value is a
76
+ # FunctionStruct
77
+ def method_missing(sym, *args, &block)
78
+ result = super(*[sym, *args], &block)
79
+ @table[_process_key(sym)] = function_bubbler(result)
80
+ end
81
+
48
82
  # @return [Class]
49
83
  def _klass
50
84
  _struct_class || ::SparkleFormation::SparkleStruct
@@ -76,7 +110,11 @@ class SparkleFormation
76
110
  result = super
77
111
  if(@self && result.nil?)
78
112
  if(_self.parameters.keys.map(&:to_s).include?(arg.to_s))
79
- ::Kernel.raise ::ArgumentError.new "No value provided for compile time parameter: `#{arg}`!"
113
+ unless(_self.parameters[arg.to_sym].key?(:default))
114
+ ::Kernel.raise ::ArgumentError.new "No value provided for compile time parameter: `#{arg}`!"
115
+ else
116
+ result = _self.parameters[arg.to_sym][:default]
117
+ end
80
118
  end
81
119
  end
82
120
  result
@@ -84,5 +122,4 @@ class SparkleFormation
84
122
  alias_method :state!, :_state
85
123
 
86
124
  end
87
-
88
125
  end
@@ -1,5 +1,5 @@
1
1
  # Unicorns and rainbows
2
2
  class SparkleFormation
3
3
  # Current library version
4
- VERSION = Gem::Version.new('1.2.0')
4
+ VERSION = Gem::Version.new('2.0.0')
5
5
  end
@@ -10,12 +10,16 @@ Gem::Specification.new do |s|
10
10
  s.description = 'Ruby DSL for programmatic orchestration API template generation'
11
11
  s.license = 'Apache-2.0'
12
12
  s.require_path = 'lib'
13
- s.add_dependency 'attribute_struct', '>= 0.2.27', '< 0.4'
14
- s.add_dependency 'multi_json'
15
- s.add_dependency 'bogo'
13
+ s.required_ruby_version = '>= 2.0'
14
+ s.add_runtime_dependency 'attribute_struct', '>= 0.3.0', '< 0.5'
15
+ s.add_runtime_dependency 'multi_json'
16
+ s.add_runtime_dependency 'bogo'
16
17
  s.add_development_dependency 'minitest'
17
18
  s.add_development_dependency 'rake'
18
19
  s.add_development_dependency 'rubocop'
20
+ s.add_development_dependency 'yard'
21
+ s.add_development_dependency 'redcarpet', '~> 2.0'
22
+ s.add_development_dependency 'github-markup'
19
23
  s.executables << 'generate_sparkle_docs'
20
24
  s.files = Dir['{lib,docs}/**/*'] + %w(sparkle_formation.gemspec README.md CHANGELOG.md LICENSE)
21
25
  end
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: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-02 00:00:00.000000000 Z
11
+ date: 2016-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: attribute_struct
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.2.27
19
+ version: 0.3.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '0.4'
22
+ version: '0.5'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.2.27
29
+ version: 0.3.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '0.4'
32
+ version: '0.5'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: multi_json
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -100,6 +100,48 @@ dependencies:
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: yard
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: redcarpet
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '2.0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '2.0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: github-markup
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
103
145
  description: Ruby DSL for programmatic orchestration API template generation
104
146
  email: chrisroberts.code@gmail.com
105
147
  executables:
@@ -132,12 +174,26 @@ files:
132
174
  - lib/sparkle_formation.rb
133
175
  - lib/sparkle_formation/aws.rb
134
176
  - lib/sparkle_formation/error.rb
177
+ - lib/sparkle_formation/function_struct.rb
178
+ - lib/sparkle_formation/provider.rb
179
+ - lib/sparkle_formation/provider/aws.rb
180
+ - lib/sparkle_formation/provider/azure.rb
181
+ - lib/sparkle_formation/provider/heat.rb
135
182
  - lib/sparkle_formation/resources.rb
136
183
  - lib/sparkle_formation/resources/aws.rb
137
184
  - lib/sparkle_formation/resources/aws_resources.json
185
+ - lib/sparkle_formation/resources/azure.rb
186
+ - lib/sparkle_formation/resources/azure_resources.json
187
+ - lib/sparkle_formation/resources/heat.rb
188
+ - lib/sparkle_formation/resources/heat_resources.json
189
+ - lib/sparkle_formation/resources/rackspace.rb
190
+ - lib/sparkle_formation/resources/rackspace_resources.json
138
191
  - lib/sparkle_formation/sparkle.rb
139
192
  - lib/sparkle_formation/sparkle_attribute.rb
140
193
  - lib/sparkle_formation/sparkle_attribute/aws.rb
194
+ - lib/sparkle_formation/sparkle_attribute/azure.rb
195
+ - lib/sparkle_formation/sparkle_attribute/heat.rb
196
+ - lib/sparkle_formation/sparkle_attribute/rackspace.rb
141
197
  - lib/sparkle_formation/sparkle_collection.rb
142
198
  - lib/sparkle_formation/sparkle_formation.rb
143
199
  - lib/sparkle_formation/sparkle_struct.rb
@@ -159,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
215
  requirements:
160
216
  - - ">="
161
217
  - !ruby/object:Gem::Version
162
- version: '0'
218
+ version: '2.0'
163
219
  required_rubygems_version: !ruby/object:Gem::Requirement
164
220
  requirements:
165
221
  - - ">="