lib/cfer/core/stack.rb in cfer-0.4.2 vs lib/cfer/core/stack.rb in cfer-0.5.0.pre.rc1

- old
+ new

@@ -1,11 +1,11 @@ module Cfer::Core # Defines the structure of a CloudFormation stack class Stack < Cfer::Block - include Cfer::Core - include Cfer::Cfn + include Cfer::Core::Functions + include Cfer::Core::Hooks # The parameters strictly as passed via command line attr_reader :input_parameters # The fully resolved parameters, including defaults and parameters fetched from an existing stack during an update @@ -135,11 +135,11 @@ # @param options [Hash] Additional attributes to add to the resource block (such as the `UpdatePolicy` for an `AWS::AutoScaling::AutoScalingGroup`) def resource(name, type, options = {}, &block) Preconditions.check_argument(/[[:alnum:]]+/ =~ name, "Resource name must be alphanumeric") clazz = Cfer::Core::Resource.resource_class(type) - rc = clazz.new(name, type, options, &block) + rc = clazz.new(name, type, self, options, &block) self[:Resources][name] = rc rc end @@ -156,83 +156,45 @@ # @return [String] The final template def to_cfn to_h.to_json end + # Gets the Cfn client, if one exists, or throws an error if one does not def client @options[:client] || raise(Cfer::Util::CferError, "Stack has no associated client.") end # Includes template code from one or more files, and evals it in the context of this stack. # Filenames are relative to the file containing the invocation of this method. def include_template(*files) include_base = options[:include_base] || File.dirname(caller.first.split(/:\d/,2).first) files.each do |file| path = File.join(include_base, file) - instance_eval(File.read(path), path) + if path.ends_with?('.json') + self.deep_merge! JSON.parse(File.read(path)) + else + instance_eval(File.read(path), path) + end end end + # Looks up a specific output of another CloudFormation stack in the same region. + # @param stack [String] The name of the stack to fetch an output from + # @param out [String] The name of the output to fetch from the stack def lookup_output(stack, out) - client = @options[:client] || raise(Cfer::Util::CferError, "Can not fetch stack outputs without a client") - client.fetch_output(stack, out) + lookup_outputs(stack).fetch(out) end + # Looks up a hash of all outputs from another CloudFormation stack in the same region. + # @param stack [String] The name of the stack to fetch outputs from def lookup_outputs(stack) client = @options[:client] || raise(Cfer::Util::CferError, "Can not fetch stack outputs without a client") client.fetch_outputs(stack) end - private - - def post_block - begin - validate_stack!(self) - rescue Cfer::Util::CferValidationError => e - Cfer::LOGGER.error "Cfer detected #{e.errors.size > 1 ? 'errors' : 'an error'} when generating the stack:" - e.errors.each do |err| - Cfer::LOGGER.error "* #{err[:error]} in Stack#{validation_contextualize(err[:context])}" - end - raise e + class << self + def extend_stack(&block) + class_eval(&block) end end - - def validate_stack!(hash) - errors = [] - context = [] - _inner_validate_stack!(hash, errors, context) - - raise Cfer::Util::CferValidationError, errors unless errors.empty? - end - - def _inner_validate_stack!(hash, errors = [], context = []) - case hash - when Hash - hash.each do |k, v| - _inner_validate_stack!(v, errors, context + [k]) - end - when Array - hash.each_index do |i| - _inner_validate_stack!(hash[i], errors, context + [i]) - end - when nil - errors << { - error: "CloudFormation does not allow nulls in templates", - context: context - } - end - end - - def validation_contextualize(err_ctx) - err_ctx.inject("") do |err_str, ctx| - err_str << - case ctx - when String - ".#{ctx}" - when Numeric - "[#{ctx}]" - end - end - end end - end