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,168 @@
1
+ require 'sparkle_formation'
2
+
3
+ class SparkleFormation
4
+ module Provider
5
+ # Azure specific implementation
6
+ module Azure
7
+
8
+ # @return [String] Type string for Azure Resource Manager stack resource
9
+ def stack_resource_type
10
+ 'Microsoft.Resources/deployments'
11
+ end
12
+
13
+ # Generate policy for stack
14
+ #
15
+ # @return [Hash]
16
+ def generate_policy
17
+ {}
18
+ end
19
+
20
+ # Apply deeply nested stacks. This is the new nesting approach and
21
+ # does not bubble parameters up to the root stack. Parameters are
22
+ # isolated to the stack resource itself and output mapping is
23
+ # automatically applied.
24
+ #
25
+ # @yieldparam stack [SparkleFormation] stack instance
26
+ # @yieldparam resource [AttributeStruct] the stack resource
27
+ # @yieldparam s_name [String] stack resource name
28
+ # @yieldreturn [Hash] key/values to be merged into resource properties
29
+ # @return [Hash] dumped stack
30
+ def apply_deep_nesting(*args, &block)
31
+ outputs = collect_outputs
32
+ nested_stacks(:with_resource).each do |stack, resource|
33
+ unless(stack.nested_stacks.empty?)
34
+ stack.apply_deep_nesting(*args)
35
+ end
36
+ stack.compile.parameters.keys!.each do |parameter_name|
37
+ if(output_name = output_matched?(parameter_name, outputs.keys))
38
+ next if outputs[output_name] == stack
39
+ stack_output = stack.make_output_available(output_name, outputs)
40
+ resource.properties.parameters._set(parameter_name).value stack_output
41
+ end
42
+ end
43
+ end
44
+ if(block_given?)
45
+ extract_templates(&block)
46
+ end
47
+ compile.dump!
48
+ end
49
+
50
+ # Apply shallow nesting. This style of nesting will bubble
51
+ # parameters up to the root stack. This type of nesting is the
52
+ # original and now deprecated, but remains for compat issues so any
53
+ # existing usage won't be automatically busted.
54
+ #
55
+ # @yieldparam resource_name [String] name of stack resource
56
+ # @yieldparam stack [SparkleFormation] nested stack
57
+ # @yieldreturn [String] Remote URL storage for template
58
+ # @return [Hash]
59
+ def apply_shallow_nesting(*args, &block)
60
+ parameters = compile.parameters
61
+ output_map = {}
62
+ nested_stacks(:with_resource, :with_name).each do |_stack, stack_resource, stack_name|
63
+ remap_nested_parameters(compile, parameters, stack_name, stack_resource, output_map)
64
+ end
65
+ extract_templates(&block)
66
+ if(args.include?(:bubble_outputs))
67
+ output_map.each do |o_name, o_val|
68
+ compile.outputs._set(o_name).value compile._stack_output(*o_val)
69
+ end
70
+ end
71
+ compile.dump!
72
+ end
73
+
74
+ # Extract output to make available for stack parameter usage at the
75
+ # current depth
76
+ #
77
+ # @param output_name [String] name of output
78
+ # @param outputs [Hash] listing of outputs
79
+ # @reutrn [Hash] reference to output value (used for setting parameter)
80
+ def make_output_available(output_name, outputs)
81
+ bubble_path = outputs[output_name].root_path - root_path
82
+ drip_path = root_path - outputs[output_name].root_path
83
+ bubble_path.each_slice(2) do |base_sparkle, ref_sparkle|
84
+ next unless ref_sparkle
85
+ base_sparkle.compile.outputs._set(output_name)._set(
86
+ :value, base_sparkle.compile._stack_output(
87
+ ref_sparkle.name, output_name
88
+ )
89
+ )
90
+ end
91
+ if(bubble_path.empty?)
92
+ if(drip_path.size == 1)
93
+ parent = drip_path.first.parent
94
+ if(parent && !parent.compile.parameters._set(output_name).nil?)
95
+ return compile.parameter!(output_name)
96
+ end
97
+ end
98
+ raise ArgumentError.new "Failed to detect available bubbling path for output `#{output_name}`. " <<
99
+ 'This may be due to a circular dependency! ' <<
100
+ "(Output Path: #{outputs[output_name].root_path.map(&:name).join(' > ')} " <<
101
+ "Requester Path: #{root_path.map(&:name).join(' > ')})"
102
+ end
103
+ result = compile._stack_output(bubble_path.first.name, output_name)
104
+ if(drip_path.size > 1)
105
+ parent = drip_path.first.parent
106
+ drip_path.unshift(parent) if parent
107
+ drip_path.each_slice(2) do |base_sparkle, ref_sparkle|
108
+ next unless ref_sparkle
109
+ base_sparkle.compile.resources[ref_sparkle.name].properties.parameters.value._set(output_name, result)
110
+ ref_sparkle.compile.parameters._set(output_name).type 'string' # TODO: <<<<------ type check and prop
111
+ result = compile._parameter(output_name)
112
+ end
113
+ end
114
+ result
115
+ end
116
+
117
+ # Extract parameters from nested stacks. Check for previous nested
118
+ # stack outputs that match parameter. If match, set parameter to use
119
+ # output. If no match, check container stack parameters for match.
120
+ # If match, set to use ref. If no match, add parameter to container
121
+ # stack parameters and set to use ref.
122
+ #
123
+ # @param template [Hash] template being processed
124
+ # @param parameters [Hash] top level parameter set being built
125
+ # @param stack_name [String] name of stack resource
126
+ # @param stack_resource [Hash] duplicate of stack resource contents
127
+ # @param output_map [Hash] mapping of output names to required stack output access
128
+ # @return [TrueClass]
129
+ # @note if parameter has includes `StackUnique` a new parameter will
130
+ # be added to container stack and it will not use outputs
131
+ def remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map)
132
+ nested_template = stack_resource.properties.stack.compile
133
+ stack_parameters = nested_template.parameters
134
+ unless(stack_parameters.nil?)
135
+ stack_parameters._keys.each do |pname|
136
+ pval = stack_parameters[pname]
137
+ unless(pval.stack_unique.nil?)
138
+ check_name = [stack_name, pname].join
139
+ else
140
+ check_name = pname
141
+ end
142
+ if(!parameters._set(check_name).nil?)
143
+ template.resources._set(stack_name).properties.parameters._set(pname).value(
144
+ template._parameter(check_name)
145
+ )
146
+ elsif(output_map[check_name])
147
+ template.resources._set(stack_name).properties.parameters._set(pname).value(
148
+ template._stack_output(*output_map[check_name])
149
+ )
150
+ else
151
+ parameters._set(check_name, pval)
152
+ template.resources._set(stack_name).properties.parameters._set(pname).value(
153
+ template._parameter(check_name)
154
+ )
155
+ end
156
+ end
157
+ end
158
+ unless(nested_template.outputs.nil?)
159
+ nested_template.outputs.keys!.each do |oname|
160
+ output_map[oname] = [stack_name, oname]
161
+ end
162
+ end
163
+ true
164
+ end
165
+
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,163 @@
1
+ require 'sparkle_formation'
2
+
3
+ class SparkleFormation
4
+ module Provider
5
+ # Heat specific implementation
6
+ module Heat
7
+
8
+ # @return [String] Type string for OpenStack HEAT stack resource
9
+ def stack_resource_type
10
+ 'OS::Heat::Stack'
11
+ end
12
+
13
+ # Generate policy for stack
14
+ #
15
+ # @return [Hash]
16
+ def generate_policy
17
+ {}
18
+ end
19
+
20
+ # Apply deeply nested stacks. This is the new nesting approach and
21
+ # does not bubble parameters up to the root stack. Parameters are
22
+ # isolated to the stack resource itself and output mapping is
23
+ # automatically applied.
24
+ #
25
+ # @yieldparam stack [SparkleFormation] stack instance
26
+ # @yieldparam resource [AttributeStruct] the stack resource
27
+ # @yieldparam s_name [String] stack resource name
28
+ # @yieldreturn [Hash] key/values to be merged into resource properties
29
+ # @return [Hash] dumped stack
30
+ def apply_deep_nesting(*args, &block)
31
+ outputs = collect_outputs
32
+ nested_stacks(:with_resource).each do |stack, resource|
33
+ unless(stack.nested_stacks.empty?)
34
+ stack.apply_deep_nesting(*args)
35
+ end
36
+ stack.compile.parameters.keys!.each do |parameter_name|
37
+ if(output_name = output_matched?(parameter_name, outputs.keys))
38
+ next if outputs[output_name] == stack
39
+ stack_output = stack.make_output_available(output_name, outputs)
40
+ resource.properties.parameters._set(parameter_name, stack_output)
41
+ end
42
+ end
43
+ end
44
+ if(block_given?)
45
+ extract_templates(&block)
46
+ end
47
+ compile.dump!
48
+ end
49
+
50
+ # Apply shallow nesting. This style of nesting will bubble
51
+ # parameters up to the root stack. This type of nesting is the
52
+ # original and now deprecated, but remains for compat issues so any
53
+ # existing usage won't be automatically busted.
54
+ #
55
+ # @yieldparam resource_name [String] name of stack resource
56
+ # @yieldparam stack [SparkleFormation] nested stack
57
+ # @yieldreturn [String] Remote URL storage for template
58
+ # @return [Hash]
59
+ def apply_shallow_nesting(*args, &block)
60
+ parameters = compile.parameters
61
+ output_map = {}
62
+ nested_stacks(:with_resource, :with_name).each do |_stack, stack_resource, stack_name|
63
+ remap_nested_parameters(compile, parameters, stack_name, stack_resource, output_map)
64
+ end
65
+ extract_templates(&block)
66
+ if(args.include?(:bubble_outputs))
67
+ output_map.each do |o_name, o_val|
68
+ compile.outputs._set(o_name).value compile._stack_output(*o_val)
69
+ end
70
+ end
71
+ compile.dump!
72
+ end
73
+
74
+ # Extract output to make available for stack parameter usage at the
75
+ # current depth
76
+ #
77
+ # @param output_name [String] name of output
78
+ # @param outputs [Hash] listing of outputs
79
+ # @reutrn [Hash] reference to output value (used for setting parameter)
80
+ def make_output_available(output_name, outputs)
81
+ bubble_path = outputs[output_name].root_path - root_path
82
+ drip_path = root_path - outputs[output_name].root_path
83
+ bubble_path.each_slice(2) do |base_sparkle, ref_sparkle|
84
+ next unless ref_sparkle
85
+ base_sparkle.compile.outputs._set(output_name)._set(
86
+ :value, base_sparkle.compile._stack_output(
87
+ ref_sparkle.name, output_name
88
+ )
89
+ )
90
+ end
91
+ if(bubble_path.empty?)
92
+ if(drip_path.size == 1)
93
+ parent = drip_path.first.parent
94
+ if(parent && !parent.compile.parameters._set(output_name).nil?)
95
+ return compile.parameter!(output_name)
96
+ end
97
+ end
98
+ raise ArgumentError.new "Failed to detect available bubbling path for output `#{output_name}`. " <<
99
+ 'This may be due to a circular dependency! ' <<
100
+ "(Output Path: #{outputs[output_name].root_path.map(&:name).join(' > ')} " <<
101
+ "Requester Path: #{root_path.map(&:name).join(' > ')})"
102
+ end
103
+ result = compile._stack_output(bubble_path.first.name, output_name)
104
+ if(drip_path.size > 1)
105
+ parent = drip_path.first.parent
106
+ drip_path.unshift(parent) if parent
107
+ drip_path.each_slice(2) do |base_sparkle, ref_sparkle|
108
+ next unless ref_sparkle
109
+ base_sparkle.compile.resources[ref_sparkle.name].properties.parameters._set(output_name, result)
110
+ ref_sparkle.compile.parameters._set(output_name).type 'string' # TODO: <<<<------ type check and prop
111
+ result = compile._parameter(output_name)
112
+ end
113
+ end
114
+ result
115
+ end
116
+
117
+ # Extract parameters from nested stacks. Check for previous nested
118
+ # stack outputs that match parameter. If match, set parameter to use
119
+ # output. If no match, check container stack parameters for match.
120
+ # If match, set to use ref. If no match, add parameter to container
121
+ # stack parameters and set to use ref.
122
+ #
123
+ # @param template [Hash] template being processed
124
+ # @param parameters [Hash] top level parameter set being built
125
+ # @param stack_name [String] name of stack resource
126
+ # @param stack_resource [Hash] duplicate of stack resource contents
127
+ # @param output_map [Hash] mapping of output names to required stack output access
128
+ # @return [TrueClass]
129
+ # @note if parameter has includes `StackUnique` a new parameter will
130
+ # be added to container stack and it will not use outputs
131
+ def remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map)
132
+ nested_template = stack_resource.properties.stack.compile
133
+ stack_parameters = nested_template.parameters
134
+ unless(stack_parameters.nil?)
135
+ stack_parameters._keys.each do |pname|
136
+ pval = stack_parameters[pname]
137
+ unless(pval.stack_unique.nil?)
138
+ check_name = [stack_name, pname].join
139
+ else
140
+ check_name = pname
141
+ end
142
+ if(!parameters._set(check_name).nil?)
143
+ template.resources._set(stack_name).properties.parameters._set(pname, template._parameter(check_name))
144
+ elsif(output_map[check_name])
145
+ template.resources._set(stack_name).properties.parameters._set(pname)
146
+ template._stack_output(*output_map[check_name])
147
+ else
148
+ parameters._set(check_name, pval)
149
+ template.resources._set(stack_name).properties.parameters._set(pname, template._parameter(check_name))
150
+ end
151
+ end
152
+ end
153
+ unless(nested_template.outputs.nil?)
154
+ nested_template.outputs.keys!.each do |oname|
155
+ output_map[oname] = [stack_name, oname]
156
+ end
157
+ end
158
+ true
159
+ end
160
+
161
+ end
162
+ end
163
+ end
@@ -5,12 +5,25 @@ class SparkleFormation
5
5
  class Resources
6
6
 
7
7
  autoload :Aws, 'sparkle_formation/resources/aws'
8
+ autoload :Azure, 'sparkle_formation/resources/azure'
9
+ autoload :Heat, 'sparkle_formation/resources/heat'
10
+ autoload :Rackspace, 'sparkle_formation/resources/rackspace'
11
+
12
+ # Characters to be removed from supplied key on matching
13
+ RESOURCE_TYPE_TR = '_'
14
+ # String to split for resource namespacing
15
+ RESOURCE_TYPE_NAMESPACE_SPLITTER = '::'
8
16
 
9
17
  class << self
10
18
 
11
19
  include SparkleFormation::Utils::AnimalStrings
12
20
  # @!parse include SparkleFormation::Utils::AnimalStrings
13
21
 
22
+ # @return [String] base registry key
23
+ def base_key
24
+ Bogo::Utility.snake(self.name.split('::').last) # rubocop:disable Style/RedundantSelf
25
+ end
26
+
14
27
  # Register resource
15
28
  #
16
29
  # @param type [String] Orchestration resource type
@@ -20,7 +33,8 @@ class SparkleFormation
20
33
  unless(class_variable_defined?(:@@registry))
21
34
  @@registry = AttributeStruct.hashish.new
22
35
  end
23
- @@registry[type] = hash
36
+ @@registry[base_key] ||= AttributeStruct.hashish.new
37
+ @@registry[base_key][type] = hash
24
38
  true
25
39
  end
26
40
 
@@ -67,11 +81,13 @@ class SparkleFormation
67
81
  # @return [String, NilClass]
68
82
  def registry_key(key)
69
83
  o_key = key
70
- key = key.to_s.tr('_', '')
84
+ key = key.to_s.tr(self.const_get(:RESOURCE_TYPE_TR), '') # rubocop:disable Style/RedundantSelf
71
85
  snake_parts = nil
72
- result = @@registry.keys.detect do |ref|
86
+ result = @@registry[base_key].keys.detect do |ref|
73
87
  ref = ref.downcase
74
- snake_parts = ref.split('::')
88
+ snake_parts = ref.split(
89
+ self.const_get(:RESOURCE_TYPE_NAMESPACE_SPLITTER) # rubocop:disable Style/RedundantSelf
90
+ )
75
91
  until(snake_parts.empty?)
76
92
  break if snake_parts.join('') == key
77
93
  snake_parts.shift
@@ -79,8 +95,10 @@ class SparkleFormation
79
95
  !snake_parts.empty?
80
96
  end
81
97
  if(result)
82
- collisions = @@registry.keys.find_all do |ref|
83
- split_ref = ref.downcase.split('::')
98
+ collisions = @@registry[base_key].keys.find_all do |ref|
99
+ split_ref = ref.downcase.split(
100
+ self.const_get(:RESOURCE_TYPE_NAMESPACE_SPLITTER) # rubocop:disable Style/RedundantSelf
101
+ )
84
102
  ref = split_ref.slice(split_ref.size - snake_parts.size, split_ref.size).join('')
85
103
  key == ref
86
104
  end
@@ -97,16 +115,15 @@ class SparkleFormation
97
115
  # @param key [String, Symbol]
98
116
  # @return [Hashish, NilClass]
99
117
  def lookup(key)
100
- @@registry[registry_key(key)]
118
+ @@registry[base_key][registry_key(key)]
101
119
  end
102
120
 
103
121
  # @return [Hashish] currently loaded AWS registry
104
122
  def registry
105
- if(class_variable_defined?(:@@registry))
106
- @@registry
107
- else
123
+ unless(class_variable_defined?(:@@registry))
108
124
  @@registry = AttributeStruct.hashish.new
109
125
  end
126
+ @@registry[base_key]
110
127
  end
111
128
 
112
129
  end
@@ -0,0 +1,42 @@
1
+ require 'sparkle_formation'
2
+
3
+ class SparkleFormation
4
+
5
+ # Resources helper
6
+ class Resources
7
+
8
+ # Azure specific resources collection
9
+ class Azure < Resources
10
+
11
+ # String to split for resource namespacing
12
+ RESOURCE_TYPE_NAMESPACE_SPLITTER = '/'
13
+
14
+ class << self
15
+
16
+ include Bogo::Memoization
17
+
18
+ # Load the builtin AWS resources
19
+ #
20
+ # @return [TrueClass]
21
+ def load!
22
+ memoize(:azure_resources, :global) do
23
+ load(
24
+ File.join(
25
+ File.dirname(__FILE__),
26
+ 'azure_resources.json'
27
+ )
28
+ )
29
+ true
30
+ end
31
+ end
32
+
33
+ # Auto load data when included
34
+ def included(_klass)
35
+ load!
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end