class CloudFormationTool::CloudFormation
Attributes
basedir[R]
Public Class Methods
new(path)
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 15 def initialize(path) log "Loading #{path}" @path = path @path = "#{@path}/cloud-formation.yaml" if File.directory? @path @path = "#{@path}.yaml" if !File.exist? @path and File.exist? "#{@path}.yaml" @basedir = File.dirname(@path) @compiled = false @params = nil begin text = File.read(@path) # remove comments because white space seen between comments can seriously psych Psych text.gsub!(/^#.*\n/,'') text = fixShorthand(text) @data = YAML.load(text).to_h rescue Psych::SyntaxError => e e.message =~ /line (\d+) column (\d+)/ lines = text.split "\n" raise CloudFormationTool::Errors::AppError, "Error parsing #{path} at line #{e.line} column #{e.column}:\n" + "#{lines[e.line-1]}\n" + "#{(' ' * (e.column - 1 ))}^- #{e.problem} #{e.context}" rescue Errno::ENOENT => e raise CloudFormationTool::Errors::AppError, "Error reading #{path}: #{e.message}" end end
parse(path)
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 9 def self.parse(path) CloudFormation.new(path) end
Public Instance Methods
compile(parameters = nil)
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 40 def compile(parameters = nil) @params = parameters unless parameters.nil? embed_includes @data = load_files(@data) end
each() { |name, param| ... }
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 202 def each compile['Parameters'].each do |name, param| yield name, param['Default'] end end
embed_includes()
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 95 def embed_includes (@data.delete(@data.keys.find{|k| k.start_with? 'Include'}) || []).each do |path| realpath = "#{@basedir}/#{path}" cfile_key = File.dirname(realpath).gsub(%r{/(.)}){|m| $1.upcase }.gsub(/\W+/,'') rewrites = Hash.new CloudFormation.new(realpath).compile.each do |category, catdata| # some categories are meta-data that we can ignore from includes next if %w(AWSTemplateFormatVersion Description).include? category case category when "Parameters" (@data[category]||={}).each do |name, param| if catdata.has_key? name next if param['Default'] == catdata[name]['Default'] if catdata[name].has_key?('Override') and catdata[name]['Override'] == false catdata.delete(name) else newname = "#{cfile_key}z#{name}" log "Rewriting conflicting parameter #{name} (='#{catdata[name]['Default']}') to #{newname}" catdata[newname] = catdata.delete name rewrites[name] = newname end else @data[category][name] = param end end else # warn against duplicate entities, resources or outputs (@data[category] ||= {}).keys.each do |key| if catdata.has_key? key raise CloudFormationTool::Errors::AppError, "Error compiling #{path} - duplicate '#{category}' item: #{key}" end end catdata = fixrefs(catdata, rewrites) end # add included properties @data[category].merge! catdata end end end
embed_includes_future()
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 85 def embed_includes_future (@data.delete(@data.keys.find{|k| k.start_with? 'Include'}) || []).each do |path| case path when Hash when String embed_included_path path end end end
fixShorthand(text)
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 51 def fixShorthand(text) text.gsub(/(?:(\s*)([^![:space:]]+))?(\s+)!(\w+)/) do |match| case $4 when *%w(Base64 FindInMap GetAtt GetAZs ImportValue Join Select Sub Split And Equals If Not Or) ($2.nil? ? "" : "#{$1}#{$2}\n#{$1} ") + "#{$3}\"Fn::#{$4}\":" when 'Ref' "#{$1}#{$2}\n#{$1} #{$3}#{$4}:" else match end end end
fixrefs(data, rmap)
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 65 def fixrefs(data, rmap) case data when Hash data.inject({}) do |h,(k,v)| h[k] = if k == "Ref" rmap[v] || v else fixrefs(v,rmap) end h end when Array data.collect do |item| fixrefs(item, rmap) end else return data end end
load_files(data, restype = nil)
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 161 def load_files(data, restype = nil) case data when Array data.collect { |data| load_files(data, restype) } when Hash # remember the current resource type restype = data['Type'] if restype.nil? and data.key?('Type') data.inject({}) do |dict, (key, val)| dict[key] = case restype when 'AWS::AutoScaling::LaunchConfiguration', 'AWS::EC2::LaunchTemplate' if (key == "UserData") and (val["File"]) # Support LaunchConfiguration UserData from file CloudInit.new("#{@basedir}/#{val["File"]}").to_base64 elsif (key == "UserData") and (val["FileTemplate"]) # Support LaunchConfiguration UserData from file with substitutions { "Fn::Base64" => { "Fn::Sub" => CloudInit.new("#{@basedir}/#{val["FileTemplate"]}").compile } } else load_files(val, restype) end when 'AWS::Lambda::Function' if key == 'Code' LambdaCode.new(val, self, data['Runtime']).to_cloudformation else load_files(val, restype) end when 'AWS::CloudFormation::Stack' if key == 'Properties' and val.key?('Template') NestedStack.new(val, self).to_cloudformation else load_files(val, restype) end else load_files(val, restype) end dict end else data end end
resolveVal(value)
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 138 def resolveVal(value) case value when Hash if value.key? 'Ref' if @params.nil? # no parameters, we are probably in a sub template, just return the ref and hope # a parent template has what it takes to resolve the ref value else # parameters are set for this template - we can try to resolve res = @params[value['Ref']] || ((@data['Parameters']||{})[value['Ref']] || {})['Default'] if res.nil? raise CloudFormationTool::Errors::AppError, "Reference #{value['Ref']} can't be resolved" end res end else raise CloudFormationTool::Errors::AppError, "Value #{value} is not a valid value or reference" end else value end end
to_yaml(parameters = {})
click to toggle source
# File lib/cloud_formation_tool/cloud_formation.rb, line 46 def to_yaml(parameters = {}) @params = parameters compile.to_yaml end