class SparkleFormation
Unicorns and rainbows
Unicorns and rainbows
Formation container
Unicorns and rainbows
Constants
- ALLOWED_GENERATION_PARAMETERS
Attributes allowed for generation parameter definitions
- DEFAULT_STACK_RESOURCE
@return [String] default stack resource name
- IGNORE_DIRECTORIES
@return [Array<String>] directory names to ignore
- PROVIDER_MAPPINGS
@return [Hash] name mappings for providers used in lookups (resources/sparkles)
- SPARKLEFORMATION_ROOT_LIBRARY
@return [String] path to root of this library
- SparklePack
Independent collection of
SparkleFormation
items- VALID_GENERATION_PARAMETER_TYPES
Allowed data types for parameters
- VALID_STACK_RESOURCES
@return [Array<String>] collection of valid stack resource types
- VERSION
Current library version
Attributes
@return [AuditLog] records of template composition
@return [Array<String>] black listed templates
@return [Hash] state hash for compile time parameters
@return [String] components path
@return [Composition]
@return [String] dynamics path
@return [Symbol] name of formation
@return [Hash] parameters for stack generation
@return [SparkleFormation] parent stack
@return [Symbol] target provider
@return [Class] Provider
resources
@return [String] registry path
@return [Sparkle] parts store
@return [String] base path
@return [Array<String>] valid stack resource types
@return [String] local path to template
Public Class Methods
Execute given block within struct context
@param base [SparkleStruct] context for block @yield block to execute @return [SparkleStruct] provided base or new struct
# File lib/sparkle_formation/sparkle_formation.rb, line 125 def build(base = nil, &block) if base || block.nil? struct = base || SparkleStruct.new struct.instance_exec(&block) struct else block end end
Insert a builtin dynamic into a context
@param dynamic_name [String, Symbol] dynamic name @param struct [SparkleStruct] context for insertion @param args [Object] parameters for dynamic @return [SparkleStruct]
# File lib/sparkle_formation/sparkle_formation.rb, line 377 def builtin_insert(dynamic_name, struct, *args, &block) if struct._self.provider_resources && lookup_key = struct._self.provider_resources.registry_key(dynamic_name) _name, _config = *args _config ||= {} __t_hashish(_config) unless _name.is_a?(SparkleFormation::FunctionStruct) __t_stringish(_name) resource_name = [ _name, _config.fetch(:resource_name_suffix, dynamic_name), ].compact.join("_").to_sym else resource_name = _name._root end _config.delete(:resource_name_suffix) new_resource = struct.resources.set!(resource_name) new_resource.type lookup_key properties = new_resource.properties config_keys = _config.keys.zip(_config.keys.map { |k| snake(k).to_s.tr("_", "") }) struct._self.provider_resources.resource(dynamic_name, :properties).each do |prop_name| key = (config_keys.detect { |k| k.last == snake(prop_name).to_s.tr("_", "") } || []).first value = _config[key] if key if value if value.is_a?(Proc) properties.set!(prop_name, &value) else properties.set!(prop_name, value) end end end new_resource.instance_exec(&block) if block struct._self.provider_resources.resource_customizer(new_resource, lookup_key) new_resource end end
Compile file
@param path [String] path to file @param args [Object] use :sparkle to return struct. provide Hash
to pass through when compiling ({:state => {}})
@return [Hashish, SparkleStruct]
# File lib/sparkle_formation/sparkle_formation.rb, line 103 def compile(path, *args) opts = args.detect { |i| i.is_a?(Hash) } || {} unless path.is_a?(String) && File.file?(path.to_s) if spath = (opts.delete(:sparkle_path) || SparkleFormation.custom_paths[:sparkle_path]) container = Sparkle.new(:root => spath) path = container.get(:template, path)[:path] end end formation = instance_eval(IO.read(path), path, 1) formation.template_path = path if args.delete(:sparkle) formation else formation.compile(opts)._dump end end
Get/set path to component files
@param path [String] path to component files @return [String] path to component files
# File lib/sparkle_formation/sparkle_formation.rb, line 62 def components_path=(path = nil) if path custom_paths[:components_directory] = path end custom_paths[:components_directory] end
@return [Hashish] custom paths
# File lib/sparkle_formation/sparkle_formation.rb, line 37 def custom_paths @_paths ||= SparkleStruct.hashish.new @_paths end
Define and register new dynamic
@param name [String, Symbol] name of dynamic @param args [Hash] dynamic metadata @option args [Hash] :parameters description of _config parameters @example
metadata describes dynamic parameters for _config hash: :item_name => {:description => 'Defines item name', :type => 'String'}
@yield dynamic block @return [TrueClass]
# File lib/sparkle_formation/sparkle_formation.rb, line 182 def dynamic(name, args = {}, &block) @dynamics ||= SparkleStruct.hashish.new dynamics[name] = SparkleStruct.hashish[ :block, block, :args, SparkleStruct.hashish[args.map(&:to_a)] ] true end
Metadata for dynamic
@param name [String, Symbol] dynamic name @return [Hashish] metadata information
# File lib/sparkle_formation/sparkle_formation.rb, line 194 def dynamic_info(name) if dynamics[name] dynamics[name][:args] ||= SparkleStruct.hashish.new else raise KeyError.new("No dynamic registered with provided name (#{name})") end end
@return [Hashish] loaded dynamics
# File lib/sparkle_formation/sparkle_formation.rb, line 32 def dynamics @dynamics ||= SparkleStruct.hashish.new end
Get/set path to dynamic files
@param path [String] path to dynamic files @return [String] path to dynamic files
# File lib/sparkle_formation/sparkle_formation.rb, line 75 def dynamics_path=(path = nil) if path custom_paths[:dynamics_directory] = path end custom_paths[:dynamics_directory] end
Extract the origin of the caller outside this library
@param cinfo [Array<String>] caller info @return [Array<String, Integer>] caller path and line number
# File lib/sparkle_formation/sparkle_formation.rb, line 208 def extract_caller(cinfo) res = cinfo.detect { |c| !c.include?(SPARKLEFORMATION_ROOT_LIBRARY) }.to_s.split(":")[0, 2] if res.size != 2 line = res.last if line.to_i.to_s != line res << 0 end if res != 2 res.unshift(:unknown) end end res end
Convert hash to SparkleStruct
instance
@param hash [Hashish] @return [SparkleStruct] @note will do best effort on camel key auto discovery
# File lib/sparkle_formation/sparkle_formation.rb, line 418 def from_hash(hash) struct = SparkleStruct.new struct._camel_keys_set(:auto_discovery) struct._load(hash) struct._camel_keys_set(nil) struct end
Insert a dynamic into a context
@param dynamic_name [String, Symbol] dynamic name @param struct [SparkleStruct] context for insertion @param args [Object] parameters for dynamic @return [SparkleStruct]
# File lib/sparkle_formation/sparkle_formation.rb, line 251 def insert(dynamic_name, struct, *args, &block) __t_stringish(dynamic_name) result = false begin opts = args.detect { |i| i.is_a?(Hash) } || {} dyn = struct._self.sparkle.get(:dynamic, dynamic_name, opts[:provider]) opts = nil raise dyn if dyn.is_a?(Exception) result = nil dyn.monochrome.each do |dynamic_item| record = struct._self.audit_log.push( type: :dynamic, name: dynamic_name, caller: extract_caller(caller), location: dynamic_item[:block].source_location, ) struct._self.wrapped_audit(record) do if result opts = args.detect { |i| i.is_a?(Hash) } if opts opts[:previous_layer_result] = result else args.push(:previous_layer_result => result) end end result = struct.instance_exec(*args, &dynamic_item[:block]) end end if block_given? result.instance_exec(&block) end rescue Error::NotFound::Dynamic record = struct._self.audit_log.push( type: :dynamic, name: dynamic_name, location: [:builtin, 0], caller: extract_caller(caller), ) result = struct._self.wrapped_audit(record) do builtin_insert(dynamic_name, struct, *args, &block) end unless result message = "Failed to locate requested dynamic block for insertion: #{dynamic_name} " \ "(valid: #{struct._self.sparkle.dynamics.fetch(struct._self.sparkle.provider, {}).keys.sort.join(", ")})" if struct._self.provider_resources && struct._self.provider_resources.registry.keys.size > 1 t_name = struct._self.provider_resources.registry.keys.first valid_t_name = Bogo::Utility.snake( t_name.split( struct._self.provider_resources.resource_type_splitter ).join("_") ) message << "\nBuiltin dynamics pattern `#{t_name}` -> `:#{Bogo::Utility.snake(valid_t_name)}`" end raise message end end result end
Load component
@param path [String] path to component @return [SparkleStruct] resulting struct
# File lib/sparkle_formation/sparkle_formation.rb, line 139 def load_component(path) instance_eval(IO.read(path), path, 1) @_struct end
Load all dynamics within a directory
@param directory [String] @return [TrueClass]
# File lib/sparkle_formation/sparkle_formation.rb, line 148 def load_dynamics!(directory) @loaded_dynamics ||= [] Dir.glob(File.join(directory, "*.rb")).each do |dyn| dyn = File.expand_path(dyn) next if @loaded_dynamics.include?(dyn) instance_eval(IO.read(dyn), dyn, 1) @loaded_dynamics << dyn end @loaded_dynamics.uniq! true end
Load all registry entries within a directory
@param directory [String] @return [TrueClass]
# File lib/sparkle_formation/sparkle_formation.rb, line 164 def load_registry!(directory) Dir.glob(File.join(directory, "*.rb")).each do |reg| reg = File.expand_path(reg) require reg end true end
Nest a template into a context
@param template [String, Symbol] template to nest @param struct [SparkleStruct] context for nesting @param args [String, Symbol] stringified and underscore joined for name @return [SparkleStruct] @note if symbol is provided for template, double underscores
will be used for directory separator and dashes will match underscores
# File lib/sparkle_formation/sparkle_formation.rb, line 318 def nest(template, struct, *args, &block) options = args.detect { |i| i.is_a?(Hash) } if options args.delete(options) else options = {} end [template, *args].compact.each do |item| __t_stringish(item) end to_nest = struct._self.sparkle.get(:template, template, options[:provider]) resource_name = template.to_s.gsub("__", "_") unless args.empty? resource_name = [ options.delete(:overwrite_name) ? nil : resource_name, args.map { |a| Bogo::Utility.snake(a) }.join("_"), ].flatten.compact.join("_").to_sym end record = struct._self.audit_log.push( type: :template, caller: extract_caller(caller), name: resource_name, location: to_nest[:path], ) struct._self.wrapped_audit(record) do resource_name = struct._process_key(resource_name.to_sym) nested_template = compile(to_nest[:path], :sparkle) nested_template.parent = struct._self nested_template.audit_log = record.audit_log nested_template.name = resource_name if options[:parameters] nested_template.compile_state = options[:parameters] end unless struct._self.sparkle.empty? nested_template.sparkle.apply(struct._self.sparkle) end nested_resource = struct.dynamic!( struct._self.stack_resource_type, resource_name, {:resource_name_suffix => nil}, &block ) # Ignore the stack resource that we generated in the # audit log since the wrapping template record will # provide the context with actual information record.audit_log.list.pop nested_resource.properties.stack nested_template # Force compilation to properly record audit log times nested_template.compile nested_resource end end
Create new instance
@param name [String, Symbol] name of formation @param options [Hash] options @option options [String] :sparkle_path custom base path @option options [String] :components_directory custom components path @option options [String] :dynamics_directory custom dynamics path @option options [String] :registry_directory custom registry path @option options [Hash] :parameters parameters for stack generation @option options [Truthy, Falsey] :disable_aws_builtins do not load builtins @yield base context
# File lib/sparkle_formation/sparkle_formation.rb, line 473 def initialize(name, options = {}, &base_block) @name = name.to_sym @component_paths = [] if options[:sparkle_collection] @sparkle = options[:sparkle_collection] if options[:sparkle] @sparkle.add_sparkle(options[:sparkle]) end else @sparkle = SparkleCollection.new if options[:sparkle] @sparkle.set_root(options[:sparkle]) else @sparkle.set_root( Sparkle.new( Smash.new.tap { |h| s_path = options.fetch(:sparkle_path, self.class.custom_paths[:sparkle_path]) if s_path h[:root] = s_path else h[:root] = :none end } ) ) end end self.provider = options.fetch(:provider, @parent ? @parent.provider : :aws) if provider == :aws || !options[:disable_aws_builtins] require "sparkle_formation/aws" end @parameters = set_generation_parameters!( options.fetch(:compile_time_parameters, options.fetch(:parameters, {})) ) @stack_resource_types = [ stack_resource_type, *options.fetch(:stack_resource_types, []), ].compact.uniq @blacklisted_templates = [name] @composition = Composition.new(self) @parent = options[:parent] @seed = Smash.new( :inherit => options[:inherit], :layering => options[:layering], ) if base_block load_block(base_block) end @audit_log = AuditLog.new @compiled = nil end
Insert a dynamic into a context
@param dynamic_name [String, Symbol] dynamic name @param struct [SparkleStruct] context for insertion @param args [Object] parameters for dynamic @return [SparkleStruct]
# File lib/sparkle_formation/sparkle_formation.rb, line 230 def registry(registry_name, struct, *args) __t_stringish(registry_name) opts = args.detect { |item| item.is_a?(Hash) } || {} reg = struct._self.sparkle.get(:registry, registry_name, opts[:provider]) record = struct._self.audit_log.push( type: :registry, name: registry_name, location: reg[:block].source_location, caller: extract_caller(caller), ) struct._self.wrapped_audit(record) do struct.instance_exec(*args, ®[:block]) end end
Get/set path to registry files
@param path [String] path to registry files @return [String] path to registry files
# File lib/sparkle_formation/sparkle_formation.rb, line 88 def registry_path=(path = nil) if path custom_paths[:registry_directory] = path end custom_paths[:registry_directory] end
Get/set path to sparkle directory
@param path [String] path to directory @return [String] path to directory
# File lib/sparkle_formation/sparkle_formation.rb, line 46 def sparkle_path=(path = nil) if path custom_paths[:sparkle_path] = path custom_paths[:components_directory] = File.join(path, "components") custom_paths[:dynamics_directory] = File.join(path, "dynamics") custom_paths[:registry_directory] = File.join(path, "registry") end custom_paths[:sparkle_path] end
Public Instance Methods
Apply deeply nested stacks. This is the new nesting approach and does not bubble parameters up to the root stack. Parameters are isolated to the stack resource itself and output mapping is automatically applied.
@yieldparam stack [SparkleFormation] stack instance @yieldparam resource [AttributeStruct] the stack resource @yieldparam s_name [String] stack resource name @yieldreturn [Hash] key/values to be merged into resource properties @return [SparkleFormation::SparkleStruct] compiled structure
# File lib/sparkle_formation/sparkle_formation.rb, line 1003 def apply_deep_nesting(*args, &block) compile end
Apply nesting logic to stack
@param nest_type [Symbol] values: :shallow, :deep (default: :deep) @return [SparkleFormation::SparkleStruct] compiled structure @note see specific version for expected block parameters
# File lib/sparkle_formation/sparkle_formation.rb, line 985 def apply_nesting(*args, &block) if args.include?(:shallow) apply_shallow_nesting(&block) else apply_deep_nesting(&block) end end
Apply shallow nesting. This style of nesting will bubble parameters up to the root stack. This type of nesting is the original and now deprecated, but remains for compat issues so any existing usage won't be automatically busted.
@yieldparam resource_name [String] name of stack resource @yieldparam stack [SparkleFormation] nested stack @yieldreturn [String] Remote URL storage for template @return [SparkleFormation::SparkleStruct] compiled structure
# File lib/sparkle_formation/sparkle_formation.rb, line 1064 def apply_shallow_nesting(*args, &block) compile end
Add block to load order
@param block [Proc] @return [TrueClass]
# File lib/sparkle_formation/sparkle_formation.rb, line 747 def block(block) composition.new_component(:__base__, &block) true end
@return [Smash<output_name:SparkleFormation>]
# File lib/sparkle_formation/sparkle_formation.rb, line 1069 def collect_outputs(*args) if args.include?(:force) || root? if !compile.outputs.nil? && !root? outputs = Smash[ compile.outputs.keys!.zip( [self] * compile.outputs.keys!.size ) ] else outputs = Smash.new end nested_stacks.each do |nested_stack| if nested_stack.is_a?(self.class) === true n_stack = nested_stack else n_stack = nested_stack._self end outputs = n_stack.collect_outputs(:force).merge(outputs) end outputs else root.collect_outputs(:force) end end
Compile the formation
@param args [Hash] @option args [Hash] :state local state parameters @return [SparkleStruct]
# File lib/sparkle_formation/sparkle_formation.rb, line 789 def compile(args = {}) if args.key?(:state) && args.is_a?(Hash) @compile_state = args[:state].to_smash unmemoize(:compile) end memoize(:compile) do # NOTE: this is where we inject inherit or layering seed_self set_compile_time_parameters! if provider && SparkleStruct.const_defined?(camel(provider)) struct_class = SparkleStruct.const_get(camel(provider)) struct_name = [SparkleStruct.name, camel(provider)].join("::") struct_class.define_singleton_method(:name) { struct_name } struct_class.define_singleton_method(:to_s) { struct_name } else struct_class = SparkleStruct end load_resources! compiled = struct_class.new compiled._set_self(self) compiled._struct_class = struct_class if struct_class.const_defined?(:CAMEL_KEYS) compiled._camel_keys = struct_class.const_get(:CAMEL_KEYS) end if struct_class.const_defined?(:CAMEL_STYLE) compiled._camel_style = struct_class.const_get(:CAMEL_STYLE) end if compile_state compiled.set_state!(compile_state) end composition.each do |item| case item when Composition::Component record = nil if item.block if item.key == "__base__" if parent.nil? record = audit_log.push( type: :template, name: name, location: item.block.source_location.first, caller: [:template, 0], ) # NOTE: Move audit log records under new record's # audit log. This allows components to be listed # logically under the template record instead of # at the same level. record.audit_log.list.replace(audit_log.list) record.audit_log.list.delete(record) audit_log.list.clear audit_log.list << record end else record = audit_log.push( type: :component, name: item.key, location: item.block.source_location.first, caller: [:template, 0], ) end wrapped_audit(record) do self.class.build(compiled, &item.block) end else sparkle.get(:component, item.key).monochrome.each do |component_block| record = audit_log.push( type: :component, name: item.key, location: component_block[:block].source_location.first, caller: [:template, 0], ) wrapped_audit(record) do self.class.build(compiled, &component_block[:block]) end end end when Composition::Override record = audit_log.push( type: :component, name: :override, location: item.block.source_location.first, caller: [:template, 0], ) if item.args && !item.args.empty? compiled._set_state(item.args) end wrapped_audit(record) do self.class.build(compiled, &item.block) end end end if compile_state && !compile_state.empty? set_compiled_state(compiled) end compiled end end
Get or set the compile time parameter setting block. If a get request the ancestor path will be searched to root
@yield block to set compile time parameters @yieldparam [SparkleFormation] @return [Proc, NilClass]
# File lib/sparkle_formation/sparkle_formation.rb, line 705 def compile_time_parameter_setter(&block) if block @compile_time_parameter_setter = block else if @compile_time_parameter_setter @compile_time_parameter_setter else parent.nil? ? nil : parent.compile_time_parameter_setter end end end
@return [Hash] dumped hash
# File lib/sparkle_formation/sparkle_formation.rb, line 1113 def dump MultiJson.load(to_json) end
Extract information from given template and integrate with current instance
@param template [SparkleFormation] @return [self]
# File lib/sparkle_formation/sparkle_formation.rb, line 606 def extract_template_data(template) # TODO: Should allow forced override here for cases like: openstack -> rackspace if provider != template.provider raise TypeError.new "This template `#{name}` cannot inherit template `#{template.name}`! Provider mismatch: `#{provider}` != `#{template.provider}`" # rubocop:disable Metrics/LineLength end template.sparkle.apply(sparkle) template.seed_self blacklisted_templates.replace( (blacklisted_templates + template.blacklisted_templates).map(&:to_s).uniq ) @parameters = template.parameters.to_smash.deep_merge(parameters.to_smash) new_composition = Composition.new(self, :components => template.composition.composite, :overrides => composition.overrides) composition.components.each do |item| if item.respond_to?(:key) && item.key == "__base__" item.key = Smash.new( :template => name, :component => :__base__, :object_id => object_id, ).checksum.to_s end new_composition.add_component(item) end @composition = new_composition self end
Extract and process nested stacks
@yieldparam stack [SparkleFormation] stack instance @yieldparam resource [AttributeStruct] the stack resource @yieldparam s_name [String] stack resource name @yieldreturn [Hash] key/values to be merged into resource properties
# File lib/sparkle_formation/sparkle_formation.rb, line 1035 def extract_templates(&block) stack_template_extractor(nested_stacks(:with_resource, :with_name), &block) end
Generate policy for stack
@return [Hash]
# File lib/sparkle_formation/sparkle_formation.rb, line 976 def generate_policy Smash.new end
@return [TrueClass, FalseClass] policies defined
# File lib/sparkle_formation/sparkle_formation.rb, line 962 def includes_policies?(stack_hash = nil) if stack_hash raise Error::Deprecated.new "Hash parameter no longer valid for this method (`#{self.class}##{__callee__}`)" end unless compile.resources.nil? compile.resources._data.any? do |r_name, r_value| !r_value.policy.nil? end end end
Inhert template structure
@param template_name [String] name of template to inherit @return [self]
# File lib/sparkle_formation/sparkle_formation.rb, line 591 def inherit_from(template_name) if blacklisted_templates.map(&:to_s).include?(template_name.to_s) raise Error::CircularInheritance.new "Circular inheritance detected between templates `#{template_name}` and `#{name}`" # rubocop:disable Metrics/LineLength end template = self.class.compile(sparkle.get(:template, template_name)[:path], :sparkle) template.blacklisted_templates.replace( (template.blacklisted_templates + blacklisted_templates).map(&:to_s).uniq ) extract_template_data(template) end
@return [TrueClass, FalseClass] includes only nested stacks
# File lib/sparkle_formation/sparkle_formation.rb, line 950 def isolated_nests?(stack_hash = nil) if stack_hash raise Error::Deprecated.new "Hash parameter no longer valid for this method (`#{self.class}##{__callee__}`)" end unless compile.resources.nil? compile.resources._data.all? do |r_name, r_value| stack_resource_type?(r_value.type) end end end
Load components into instance
@param args [String, Symbol] Symbol component names or String paths @return [self]
# File lib/sparkle_formation/sparkle_formation.rb, line 758 def load(*args, &user_block) args.each do |thing| if thing.is_a?(String) # NOTE: This needs to be deprecated and removed # TODO: deprecate key = File.basename(thing.to_s).sub(".rb", "") composition.new_component(key, &self.class.load_component(thing)) else composition.new_component(thing) end end if block_given? block(user_block) end self end
Extract output to make available for stack parameter usage at the current depth
@param output_name [String] name of output @param outputs [Hash] listing of outputs @return [Hash] reference to output value (used for setting parameter)
# File lib/sparkle_formation/sparkle_formation.rb, line 1025 def make_output_available(output_name, outputs) {} end
Merge previous layer template structure
@return [self]
# File lib/sparkle_formation/sparkle_formation.rb, line 579 def merge_previous! my_index = sparkle.get(:template, name).spectrum.find_index do |item| item[:path] == template_path end template = self.class.compile(sparkle.get(:template, name).layer_at(my_index - 1)[:path], :sparkle) extract_template_data(template) end
@return [TrueClass, FalseClass] includes nested stacks
# File lib/sparkle_formation/sparkle_formation.rb, line 938 def nested?(stack_hash = nil) if stack_hash raise Error::Deprecated.new "Hash parameter no longer valid for this method (`#{self.class}##{__callee__}`)" end unless compile.resources.nil? compile.resources._data.any? do |r_name, r_value| stack_resource_type?(r_value.type) end end end
@return [Array<SparkleFormation>]
# File lib/sparkle_formation/sparkle_formation.rb, line 916 def nested_stacks(*args) if compile[:resources] compile.resources.keys!.map do |key| if stack_resource_type?(compile.resources[key].type) if !compile.resources[key].properties.stack.nil? result = [compile.resources[key].properties.stack] if args.include?(:with_resource) result.push(compile[:resources][key]) end if args.include?(:with_name) result.push(key) end result.size == 1 ? result.first : result end end end.compact else [] end end
Check if parameter name matches an output name
@param p_name [String, Symbol] parameter name @param output_names [Array<String>] list of available outputs @return [String, NilClass] matching output name @note will auto downcase name prior to comparison
# File lib/sparkle_formation/sparkle_formation.rb, line 1013 def output_matched?(p_name, output_names) output_names.detect do |o_name| Bogo::Utility.snake(o_name).tr("_", "") == Bogo::Utility.snake(p_name).tr("_", "") end end
Registers block into overrides
@param args [Hash] optional arguments to provide state @yield override block
# File lib/sparkle_formation/sparkle_formation.rb, line 779 def overrides(args = {}, &block) composition.new_override(args, &block) self end
Set the parent template
@param p [SparkleFormation] parent template @return [self]
# File lib/sparkle_formation/sparkle_formation.rb, line 531 def parent=(p) unless p.is_a?(SparkleFormation) raise TypeError, "Expected `SparkleFormation` but received `#{p.class.name}`" end @parent = p @audit_log = p.audit_log self end
Set remote API target for template to allow loading of provider specific helpers and data if available. Setting to a false-y value will disable helpers loading
@param val [String, Symbol, NilClass, FalseClass] remote provider @return [Symbol, NilClass]
# File lib/sparkle_formation/sparkle_formation.rb, line 645 def provider=(val) if val @provider = Bogo::Utility.snake(val).to_sym provider_klass = Bogo::Utility.camel(@provider.to_s) if Provider.const_defined?(provider_klass) extend Provider.const_get(provider_klass) end sparkle.provider = val @provider else @provider = nil end end
Clear compiled stack if cached and perform compilation again
@return [SparkleStruct]
# File lib/sparkle_formation/sparkle_formation.rb, line 910 def recompile unmemoize(:compile) compile end
Extract parameters from nested stacks. Check for previous nested stack outputs that match parameter. If match, set parameter to use output. If no match, check container stack parameters for match. If match, set to use ref. If no match, add parameter to container stack parameters and set to use ref.
@param template [Hash] template being processed @param parameters [Hash] top level parameter set being built @param stack_name [String] name of stack resource @param stack_resource [Hash] duplicate of stack resource contents @param output_map [Hash] mapping of output names to required stack output access @return [TrueClass] @note if parameter has includes `StackUnique` a new parameter will
be added to container stack and it will not use outputs
# File lib/sparkle_formation/sparkle_formation.rb, line 1108 def remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map) true end
@return [SparkleFormation] root stack
# File lib/sparkle_formation/sparkle_formation.rb, line 668 def root if parent parent.root else self end end
@return [TrueClass, FalseClass] current stack is root
# File lib/sparkle_formation/sparkle_formation.rb, line 686 def root? root == self end
@return [Array<SparkleFormation] path to root
# File lib/sparkle_formation/sparkle_formation.rb, line 677 def root_path if parent [*parent.root_path, self].compact else [self] end end
Update underlying data structures based on inherit or layering behavior if defined for this template
@param options [Hash] @return [self]
# File lib/sparkle_formation/sparkle_formation.rb, line 560 def seed_self memoize(:seed) do options = @seed if options[:inherit] && options[:layering].to_s == "merge" raise ArgumentError.new "Cannot merge and inherit!" end if options[:inherit] inherit_from(options[:inherit]) elsif options[:layering].to_s == "merge" merge_previous! end true end self end
Set the compile time parameters for the stack if the setter proc is available
# File lib/sparkle_formation/sparkle_formation.rb, line 719 def set_compile_time_parameters! if compile_time_parameter_setter compile_time_parameter_setter.call(self) end end
Set the current compile_state
into the compiled result
@param compiled [AttributeStruct] @return [AttributeStruct]
# File lib/sparkle_formation/sparkle_formation.rb, line 894 def set_compiled_state(compiled) storage_compile_state = Smash.new parameters.each do |param_key, param_config| if param_config.fetch(:type, "string").to_s.downcase.to_sym != :complex storage_compile_state[param_key] = compile_state[param_key] end end unless storage_compile_state.empty? compiled.outputs.compile_state.value MultiJson.dump(storage_compile_state) end compiled end
Validation parameters used for template generation to ensure they are in the expected format
@param params [Hash] parameter set @return [Hash] parameter set @raise [ArgumentError]
# File lib/sparkle_formation/sparkle_formation.rb, line 731 def set_generation_parameters!(params) params.each do |name, value| unless value.is_a?(Hash) raise TypeError.new("Expecting `Hash` type. Received `#{value.class}`") end if key = value.keys.detect { |k| !ALLOWED_GENERATION_PARAMETERS.include?(k.to_s) } raise ArgumentError.new("Invalid generation parameter key provided `#{key}`") end end params end
@return [Hash] dumped hash
# File lib/sparkle_formation/sparkle_formation.rb, line 1118 def sparkle_dump MultiJson.load( MultiJson.dump( compile.sparkle_dump! ) ) end
@return [String] provider stack resource type
# File lib/sparkle_formation/sparkle_formation.rb, line 635 def stack_resource_type DEFAULT_STACK_RESOURCE end
Check if type is a registered stack type
@param type [String] @return [TrueClass, FalseClass]
# File lib/sparkle_formation/sparkle_formation.rb, line 663 def stack_resource_type?(type) stack_resource_types.include?(type) end
Run the stack extraction
@param x_stacks [Array<Array<SparkleFormation, SparkleStruct
, String>>]
# File lib/sparkle_formation/sparkle_formation.rb, line 1042 def stack_template_extractor(x_stacks, &block) x_stacks.each do |stack, resource, s_name| unless stack.nested_stacks.empty? stack_template_extractor(stack.nested_stacks(:with_resource, :with_name), &block) end resource.properties._delete(:stack) s_parent = resource.properties.stack stack.compile._parent(s_parent) resource.properties.set!(:stack, stack.compile) block.call(s_name, stack, resource) end end
@return [String] dumped hash JSON
# File lib/sparkle_formation/sparkle_formation.rb, line 1127 def to_json(*args) # NOTE: Ported in from batali # Prevent stupid conversion errors of # JSON::Ext::Generator::State into Hash args = args.map do |argument| argument.respond_to?(:to_h) ? argument.to_h : argument end MultiJson.dump(compile.dump!, *args) end
Wrap given block within audit log of given record
@param record [AuditLog::Record] @return [Object] result of yield
# File lib/sparkle_formation/sparkle_formation.rb, line 544 def wrapped_audit(record) start_log = audit_log start_time = Time.now.to_f @audit_log = record ? record.audit_log : start_log result = yield if block_given? record.compile_duration = Time.now.to_f - start_time if record result ensure @audit_log = start_log end
Protected Instance Methods
Load provider specific resources handling
# File lib/sparkle_formation/sparkle_formation.rb, line 1140 def load_resources! if provider && @provider_resources.nil? provider_name = camel(PROVIDER_MAPPINGS.fetch(provider, provider)) if Resources.const_defined?(provider_name) @provider_resources = Resources.const_get(provider_name) provider_resources.load! end end end