Class: SparkleFormation
- Inherits:
-
Object
- Object
- SparkleFormation
- Extended by:
- Utils::AnimalStrings
- Includes:
- Utils::AnimalStrings
- Defined in:
- lib/sparkle_formation/utils.rb,
lib/sparkle_formation.rb,
lib/sparkle_formation/aws.rb,
lib/sparkle_formation/version.rb,
lib/sparkle_formation/translation.rb,
lib/sparkle_formation/sparkle_struct.rb,
lib/sparkle_formation/translation/heat.rb,
lib/sparkle_formation/sparkle_attribute.rb,
lib/sparkle_formation/sparkle_formation.rb,
lib/sparkle_formation/translation/rackspace.rb
Overview
Formation container
Defined Under Namespace
Modules: SparkleAttribute, Utils Classes: Aws, Cache, Registry, SparkleStruct, Translation
Constant Summary collapse
- VERSION =
Current library version
Gem::Version.new('0.2.8')
- IGNORE_DIRECTORIES =
Returns directory names to ignore.
[ 'components', 'dynamics', 'registry' ]
Instance Attribute Summary collapse
-
#components ⇒ Array
readonly
Components to load.
-
#components_directory ⇒ String
readonly
Components path.
-
#dynamics_directory ⇒ String
readonly
Dynamics path.
-
#load_order ⇒ Array
readonly
Order of loading.
-
#name ⇒ Symbol
readonly
Name of formation.
-
#registry_directory ⇒ String
readonly
Registry path.
-
#sparkle_path ⇒ String
readonly
Base path.
Class Method Summary collapse
-
.build(base = nil) { ... } ⇒ SparkleStruct
Execute given block within struct context.
-
.builtin_insert(dynamic_name, struct, *args, &block) ⇒ SparkleStruct
Insert a builtin dynamic into a context.
-
.compile(path, *args) ⇒ Hashish, SparkleStruct
Compile file.
-
.components_path=(path = nil) ⇒ String
(also: components_path)
Get/set path to component files.
-
.custom_paths ⇒ Hashish
Custom paths.
-
.dynamic(name, args = {}) { ... } ⇒ TrueClass
Define and register new dynamic.
-
.dynamic_info(name) ⇒ Hashish
(also: dynamic_information)
Metadata for dynamic.
-
.dynamics ⇒ Hashish
Loaded dynamics.
-
.dynamics_path=(path = nil) ⇒ String
(also: dynamics_path)
Get/set path to dynamic files.
-
.from_hash(hash) ⇒ SparkleStruct
Convert hash to SparkleStruct instance.
-
.insert(dynamic_name, struct, *args, &block) ⇒ SparkleStruct
Insert a dynamic into a context.
-
.load_component(path) ⇒ SparkleStruct
Load component.
-
.load_dynamics!(directory) ⇒ TrueClass
Load all dynamics within a directory.
-
.load_registry!(directory) ⇒ TrueClass
Load all registry entries within a directory.
-
.nest(template, struct, *args, &block) ⇒ SparkleStruct
Nest a template into a context.
-
.registry_path=(path = nil) ⇒ String
(also: registry_path)
Get/set path to registry files.
-
.sparkle_path=(path = nil) ⇒ String
(also: sparkle_path)
Get/set path to sparkle directory.
Instance Method Summary collapse
-
#apply_nesting {|template_name, template| ... } ⇒ Hash
Apply stack nesting logic.
-
#block(block) ⇒ TrueClass
(also: #load_block)
Add block to load order.
-
#compile ⇒ SparkleStruct
Compile the formation.
-
#dump ⇒ Hash
Dumped hash.
-
#initialize(name, options = {}) { ... } ⇒ SparkleFormation
constructor
Create new instance.
-
#isolated_nests? ⇒ TrueClass, FalseClass
Includes only nested stacks.
-
#load(*args) ⇒ self
Load components into instance.
-
#nested? ⇒ TrueClass, FalseClass
Includes nested stacks.
-
#overrides(args = {}) { ... } ⇒ Object
Registers block into overrides.
-
#recompile ⇒ SparkleStruct
Clear compiled stack if cached and perform compilation again.
-
#remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map) ⇒ TrueClass
Extract parameters from nested stacks.
-
#to_json ⇒ String
Dumped hash JSON.
Methods included from Utils::AnimalStrings
Constructor Details
#initialize(name, options = {}) { ... } ⇒ SparkleFormation
Create new instance
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 314 def initialize(name, ={}, &block) @name = name.to_sym @sparkle_path = [:sparkle_path] || self.class.custom_paths[:sparkle_path] || File.join(Dir.pwd, 'cloudformation') @components_directory = [:components_directory] || self.class.custom_paths[:components_directory] || File.join(sparkle_path, 'components') @dynamics_directory = [:dynamics_directory] || self.class.custom_paths[:dynamics_directory] || File.join(sparkle_path, 'dynamics') @registry_directory = [:registry_directory] || self.class.custom_paths[:registry_directory] || File.join(sparkle_path, 'registry') self.class.load_dynamics!(@dynamics_directory) self.class.load_registry!(@registry_directory) unless([:disable_aws_builtins]) require 'sparkle_formation/aws' SfnAws.load! end @components = SparkleStruct.hashish.new @load_order = [] @overrides = [] if(block) load_block(block) end @compiled = nil end |
Instance Attribute Details
#components ⇒ Array (readonly)
Returns components to load.
300 301 302 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 300 def components @components end |
#components_directory ⇒ String (readonly)
Returns components path.
294 295 296 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 294 def components_directory @components_directory end |
#dynamics_directory ⇒ String (readonly)
Returns dynamics path.
296 297 298 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 296 def dynamics_directory @dynamics_directory end |
#load_order ⇒ Array (readonly)
Returns order of loading.
302 303 304 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 302 def load_order @load_order end |
#name ⇒ Symbol (readonly)
Returns name of formation.
290 291 292 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 290 def name @name end |
#registry_directory ⇒ String (readonly)
Returns registry path.
298 299 300 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 298 def registry_directory @registry_directory end |
#sparkle_path ⇒ String (readonly)
Returns base path.
292 293 294 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 292 def sparkle_path @sparkle_path end |
Class Method Details
.build(base = nil) { ... } ⇒ SparkleStruct
Execute given block within struct context
117 118 119 120 121 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 117 def build(base=nil, &block) struct = base || SparkleStruct.new struct.instance_exec(&block) @_struct = struct end |
.builtin_insert(dynamic_name, struct, *args, &block) ⇒ SparkleStruct
Insert a builtin dynamic into a context
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 250 def builtin_insert(dynamic_name, struct, *args, &block) if(defined?(SfnAws) && lookup_key = SfnAws.registry_key(dynamic_name)) _name, _config = *args _config ||= {} return unless _name new_resource = struct.resources.__send__("#{_name}_#{dynamic_name}".to_sym) new_resource.type lookup_key properties = new_resource.properties SfnAws.resource(dynamic_name, :properties).each do |prop_name| value = [prop_name, snake(prop_name)].map do |key| _config[key] || _config[key.to_sym] end.compact.first if(value) if(value.is_a?(Proc)) properties.__send__(prop_name).instance_exec(&value) else properties.__send__(prop_name, value) end end end new_resource.instance_exec(&block) if block new_resource end end |
.compile(path, *args) ⇒ Hashish, SparkleStruct
Compile file
107 108 109 110 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 107 def compile(path, *args) formation = self.instance_eval(IO.read(path), path, 1) args.include?(:sparkle) ? formation : formation.compile._dump end |
.components_path=(path = nil) ⇒ String Also known as: components_path
Get/set path to component files
70 71 72 73 74 75 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 70 def components_path=(path=nil) if(path) custom_paths[:components_directory] = path end custom_paths[:components_directory] end |
.custom_paths ⇒ Hashish
Returns custom paths.
46 47 48 49 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 46 def custom_paths @_paths ||= SparkleStruct.hashish.new @_paths end |
.dynamic(name, args = {}) { ... } ⇒ TrueClass
Define and register new dynamic
170 171 172 173 174 175 176 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 170 def dynamic(name, args={}, &block) @dynamics ||= SparkleStruct.hashish.new dynamics[name] = SparkleStruct.hashish[ :block, block, :args, SparkleStruct.hashish[args.map(&:to_a)] ] true end |
.dynamic_info(name) ⇒ Hashish Also known as: dynamic_information
Metadata for dynamic
182 183 184 185 186 187 188 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 182 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 |
.dynamics ⇒ Hashish
Returns loaded dynamics.
41 42 43 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 41 def dynamics @dynamics ||= SparkleStruct.hashish.new end |
.dynamics_path=(path = nil) ⇒ String Also known as: dynamics_path
Get/set path to dynamic files
82 83 84 85 86 87 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 82 def dynamics_path=(path=nil) if(path) custom_paths[:dynamics_directory] = path end custom_paths[:dynamics_directory] end |
.from_hash(hash) ⇒ SparkleStruct
will do best effort on camel key auto discovery
Convert hash to SparkleStruct instance
280 281 282 283 284 285 286 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 280 def from_hash(hash) struct = SparkleStruct.new struct._camel_keys_set(:auto_discovery) struct._load(hash) struct._camel_keys_set(nil) struct end |
.insert(dynamic_name, struct, *args, &block) ⇒ SparkleStruct
Insert a dynamic into a context
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 197 def insert(dynamic_name, struct, *args, &block) result = false if(@dynamics && @dynamics[dynamic_name]) result = struct.instance_exec(*args, &@dynamics[dynamic_name][:block]) if(block_given?) result.instance_exec(&block) end result = struct else result = builtin_insert(dynamic_name, struct, *args, &block) end unless(result) raise "Failed to locate requested dynamic block for insertion: #{dynamic_name} (valid: #{(@dynamics || {}).keys.sort.join(', ')})" end result end |
.load_component(path) ⇒ SparkleStruct
Load component
127 128 129 130 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 127 def load_component(path) self.instance_eval(IO.read(path), path, 1) @_struct end |
.load_dynamics!(directory) ⇒ TrueClass
Load all dynamics within a directory
136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 136 def load_dynamics!(directory) @loaded_dynamics ||= [] Dir.glob(File.join(directory, '*.rb')).each do |dyn| dyn = File.(dyn) next if @loaded_dynamics.include?(dyn) self.instance_eval(IO.read(dyn), dyn, 1) @loaded_dynamics << dyn end @loaded_dynamics.uniq! true end |
.load_registry!(directory) ⇒ TrueClass
Load all registry entries within a directory
152 153 154 155 156 157 158 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 152 def load_registry!(directory) Dir.glob(File.join(directory, '*.rb')).each do |reg| reg = File.(reg) require reg end true end |
.nest(template, struct, *args, &block) ⇒ SparkleStruct
if symbol is provided for template, double underscores will be used for directory separator and dashes will match underscores
Nest a template into a context
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 222 def nest(template, struct, *args, &block) spath = SparkleFormation.new('stub').sparkle_path resource_name = [template.to_s.gsub(/(\/|__|-)/, '_'), *args].compact.join('_').to_sym path = template.is_a?(Symbol) ? template.to_s.gsub('__', '/') : template.to_s file = Dir.glob(File.join(spath, '**', '**', '*.rb')).detect do |local_path| strip_path = local_path.sub(spath, '').sub(/^\//, '').tr('-', '_').sub('.rb', '') strip_path == path end unless(file) raise ArgumentError.new("Failed to locate nested stack file! (#{template.inspect} -> #{path.inspect})") end instance = self.instance_eval(IO.read(file), file, 1) struct.resources.set!(resource_name) do type 'AWS::CloudFormation::Stack' end struct.resources.__send__(resource_name).properties.stack instance.compile if(block_given?) struct.resources.__send__(resource_name).instance_exec(&block) end struct.resources.__send__(resource_name) end |
.registry_path=(path = nil) ⇒ String Also known as: registry_path
Get/set path to registry files
94 95 96 97 98 99 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 94 def registry_path=(path=nil) if(path) custom_paths[:registry_directory] = path end custom_paths[:registry_directory] end |
.sparkle_path=(path = nil) ⇒ String Also known as: sparkle_path
Get/set path to sparkle directory
55 56 57 58 59 60 61 62 63 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 55 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 |
Instance Method Details
#apply_nesting {|template_name, template| ... } ⇒ Hash
Apply stack nesting logic. Will extract unique parameters from nested stacks, update refs to use sibling stack outputs where required and extract nested stack templates for remote persistence
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 432 def apply_nesting hash = compile.dump! stacks = Hash[ hash['Resources'].find_all do |r_name, resource| [r_name, MultiJson.load(MultiJson.dump(resource))] end ] parameters = hash.fetch('Parameters', {}) output_map = {} stacks.each do |stack_name, stack_resource| remap_nested_parameters(hash, parameters, stack_name, stack_resource, output_map) end hash['Parameters'] = parameters hash['Resources'].each do |resource_name, resource| if(resource['Type'] == 'AWS::CloudFormation::Stack') stack = resource['Properties'].delete('Stack') resource['Properties']['TemplateURL'] = yield(resource_name, stack) end end hash end |
#block(block) ⇒ TrueClass Also known as: load_block
Add block to load order
347 348 349 350 351 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 347 def block(block) @components[:__base__] = self.class.build(&block) @load_order << :__base__ true end |
#compile ⇒ SparkleStruct
Compile the formation
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 384 def compile unless(@compiled) compiled = SparkleStruct.new @load_order.each do |key| compiled._merge!(components[key]) end @overrides.each do |override| if(override[:args] && !override[:args].empty?) compiled._set_state(override[:args]) end self.class.build(compiled, &override[:block]) end @compiled = compiled end @compiled end |
#dump ⇒ Hash
Returns dumped hash.
509 510 511 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 509 def dump MultiJson.load(self.to_json) end |
#isolated_nests? ⇒ TrueClass, FalseClass
Returns includes only nested stacks.
417 418 419 420 421 422 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 417 def isolated_nests? hash = compile.dump! hash.fetch('Resources', {}).all? do |name, resource| resource['Type'] == 'AWS::CloudFormation::Stack' end end |
#load(*args) ⇒ self
Load components into instance
358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 358 def load(*args) args.each do |thing| if(thing.is_a?(Symbol)) path = File.join(components_directory, "#{thing}.rb") else path = thing end key = File.basename(path).sub('.rb', '') components[key] = self.class.load_component(path) @load_order << key end self end |
#nested? ⇒ TrueClass, FalseClass
Returns includes nested stacks.
410 411 412 413 414 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 410 def nested? !!compile.dump!['Resources'].detect do |r_name, resource| resource['Type'] == 'AWS::CloudFormation::Stack' end end |
#overrides(args = {}) { ... } ⇒ Object
Registers block into overrides
376 377 378 379 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 376 def overrides(args={}, &block) @overrides << {:args => args, :block => block} self end |
#recompile ⇒ SparkleStruct
Clear compiled stack if cached and perform compilation again
404 405 406 407 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 404 def recompile @compiled = nil compile end |
#remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map) ⇒ TrueClass
if parameter has includes ‘StackUnique` a new parameter will be added to container stack and it will not use outputs
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.
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 468 def remap_nested_parameters(template, parameters, stack_name, stack_resource, output_map) stack_parameters = stack_resource['Properties']['Stack']['Parameters'] if(stack_parameters) template['Resources'][stack_name]['Properties']['Parameters'] ||= {} stack_parameters.each do |pname, pval| if(pval['StackUnique']) check_name = [stack_name, pname].join else check_name = pname end if(parameters.keys.include?(check_name)) if(parameters[check_name]['Type'] == 'CommaDelimitedList') new_val = {'Fn::Join' => [',', {'Ref' => check_name}]} else new_val = {'Ref' => check_name} end template['Resources'][stack_name]['Properties']['Parameters'][pname] = new_val elsif(output_map[check_name]) template['Resources'][stack_name]['Properties']['Parameters'][pname] = { 'Fn::GetAtt' => output_map[check_name] } else if(pval['Type'] == 'CommaDelimitedList') new_val = {'Fn::Join' => [',', {'Ref' => check_name}]} else new_val = {'Ref' => check_name} end template['Resources'][stack_name]['Properties']['Parameters'][pname] = new_val parameters[check_name] = pval end end end if(stack_resource['Properties']['Stack']['Outputs']) stack_resource['Properties']['Stack']['Outputs'].keys.each do |oname| output_map[oname] = [stack_name, "Outputs.#{oname}"] end end true end |
#to_json ⇒ String
Returns dumped hash JSON.
514 515 516 |
# File 'lib/sparkle_formation/sparkle_formation.rb', line 514 def to_json MultiJson.dump(compile.dump!) end |