class MkStack::Template

A CloudFormation template

Attributes

format[R]
limit[R]
sections[R]

Public Class Methods

new(format = "json", argv = nil) click to toggle source
# File lib/mkstack/template.rb, line 37
def initialize(format = "json", argv = nil)
  @format = format

  @sections = {
    "AWSTemplateFormatVersion" => Section.new("AWSTemplateFormatVersion", String, nil),
    "Description" => Section.new("Description", String, 1024),

    "Conditions" => Section.new("Conditions", Hash, nil),
    "Mappings"   => Section.new("Mappings",   Hash, 200),
    "Metadata"   => Section.new("Metadata",   Hash, nil),
    "Outputs"    => Section.new("Outputs",    Hash, 200),
    "Parameters" => Section.new("Parameters", Hash, 200),
    "Resources"  => Section.new("Resources",  Hash, 500),
    "Transform"  => Section.new("Transform",  Hash, nil),
  }
  @limit = 51200

  # Keep track of parsed files to avoid loops
  @parsed = {}

  # Save a binding so ERB can reuse it instead of creating a new one
  # every time we load a file.  This allows ERB code in one file to
  # be referenced in another.
  @binding = binding
end

Public Instance Methods

[](section) click to toggle source

Shorthand accessor for template sections

# File lib/mkstack/template.rb, line 64
def [](section); @sections[section]; end
exceeds_limit?() click to toggle source

Check if the template exceeds the AWS limit

# File lib/mkstack/template.rb, line 70
def exceeds_limit?; limit && length > limit; end
length() click to toggle source

Return the length of the entire template

# File lib/mkstack/template.rb, line 67
def length; to_json.to_s.length; end
merge(file, erb) click to toggle source

Merge contents of a file

# File lib/mkstack/template.rb, line 75
def merge(file, erb)
  contents = load(file, erb)

  begin
    # Try JSON
    cfn = JSON.load(contents)
  rescue Exception => e
    # Try YAML
    add_tags
    cfn = YAML.safe_load(contents, [IntrinsicShort])
    @format = "yaml"
  end

  # Merge sections that are present in the file
  @sections.each { |name, section| section.merge(cfn[name]) if cfn[name] }

  # Look for Includes and merge them
  # Files are Included relative to the file with the Include directive
  cfn["Include"].each do |file|
    Dir.chdir(File.dirname(file)) { self.merge(File.basename(file), erb) }
  end if cfn["Include"]
end
pp() click to toggle source

Format contents

# File lib/mkstack/template.rb, line 109
def pp
  case @format
  when "json"
    to_hash.to_json
  when "yaml"
    to_hash.to_yaml({ line_width: -1 }) # Keep Psych from splitting "long" lines
  else
    to_hash
  end
end
validate() click to toggle source

Call ValidateTemplate

# File lib/mkstack/template.rb, line 101
def validate
  require "aws-sdk-cloudformation"
  Aws::CloudFormation::Client.new.validate_template({ template_body: pp })
end

Private Instance Methods

add_tags() click to toggle source

List of intrinsic functions that look like undefined local tags

# File lib/mkstack/template.rb, line 150
def add_tags
  [
    "Base64",
    "Cidr",
    "FindInMap",
    "GetAtt",
    "GetAZs",
    "ImportValue",
    "Join",
    "Ref",
    "Select",
    "Split",
    "Transform",
    "And",
    "Equals",
    "If",
    "Not",
    "Or",
    "Sub",
  ].each do |function|
    YAML::add_tag("!#{function}", IntrinsicShort)
  end
end
load(file, erb = true) click to toggle source

Read file and (optionally) perform ERB processing on it

# File lib/mkstack/template.rb, line 133
def load(file, erb = true)
  path = File.expand_path(file)
  raise KeyError if @parsed.has_key?(path)

  $logger.info { "Loading #{file}" } if $logger

  contents = File.read(file)
  contents = ERB.new(contents).result(@binding) if erb

  @parsed[path] = true

  return contents
end
to_hash() click to toggle source

Create a hash of each populated section's contents

# File lib/mkstack/template.rb, line 124
def to_hash
  h = Hash.new
  @sections.each { |k, v| h[k] = v.contents if v.length > 0 }
  h
end