class SparkleFormation::Translation

Translator

Constants

FN_MAPPING

@return [Hash] mapping for intrinsic functions

REF_MAPPING

@return [Hash] mapping for pseudo-parameters

Attributes

logger[R]

@return [Logger] current logger

options[R]

@return [Hash] extra options (generally used by translation implementations)

original[R]

@return [Hash] original template

template[R]

@return [Hash] duplicated template (full deep copy)

translated[R]

@return [Hash] current translation

Public Class Methods

new(template_hash, args = {}) click to toggle source

Create new instance

@param template_hash [Hash] stack template @param args [Hash] @option args [Logger] :logger custom logger @option args [Hash] :parameters parameters for stack creation @option args [Hash] :options options for translation

# File lib/sparkle_formation/translation.rb, line 32
def initialize(template_hash, args = {})
  @original = template_hash.dup
  @template = template_hash.to_smash
  @translated = {}
  @logger = args.fetch(:logger, Logger.new($stdout))
  @parameters = args[:parameters] || {}
  @options = args[:options] || {}
end

Public Instance Methods

apply_function(hash, funcs = []) click to toggle source

Apply function if possible

@param hash [Hash] @param funcs [Array] allowed functions @return [Hash] @note also allows 'Ref' within funcs to provide mapping

replacements using the REF_MAPPING constant
# File lib/sparkle_formation/translation.rb, line 300
def apply_function(hash, funcs = [])
  k, v = hash.first
  if hash.size == 1 && (k.start_with?("Fn") || k == "Ref") && (funcs.empty? || funcs.include?(k))
    case k
    when "Fn::Join"
      v.last.join(v.first)
    when "Fn::FindInMap"
      map_holder = mappings[v[0]]
      if map_holder
        map_item = map_holder[dereference(v[1])]
        if map_item
          map_item[v[2]]
        else
          raise "Failed to find mapping item! (#{v[0]} -> #{v[1]})"
        end
      else
        raise "Failed to find mapping! (#{v[0]})"
      end
    when "Ref"
      {"Ref" => self.class.const_get(:REF_MAPPING).fetch(v, v)}
    else
      hash
    end
  else
    hash
  end
end
apply_rename(hash, names = []) click to toggle source

Apply function if possible

@param hash [Hash] @param names [Array<Symbol>] enable renaming (:ref, :fn) @return [Hash] @note remapping references to constants:

REF_MAPPING for Ref maps
FN_MAPPING for Fn maps
# File lib/sparkle_formation/translation.rb, line 258
def apply_rename(hash, names = [])
  k, v = hash.first
  if hash.size == 1
    if k.start_with?("Fn::")
      {self.class.const_get(:FN_MAPPING).fetch(k, k) => attr_mapping(*v)}
    elsif k == "Ref"
      if resources.key?(v)
        {"get_resource" => v}
      else
        {"get_param" => self.class.const_get(:REF_MAPPING).fetch(v, v)}
      end
    else
      hash
    end
  else
    hash
  end
end
attr_mapping(resource_name, value) click to toggle source

Apply `GetAttr` mapping if available

@param resource_name [String] @param value [String] @return [Array]

# File lib/sparkle_formation/translation.rb, line 282
def attr_mapping(resource_name, value)
  result = [resource_name, value]
  if r = resources[resource_name]
    attr_map = self.class.const_get(:FN_ATT_MAPPING)
    if attr_map[r["Type"]] && replacement = attr_map[r["Type"]][value]
      result = [resource_name, *[replacement].flatten.compact]
    end
  end
  result
end
default_key_format(key) click to toggle source

Default formatting for keys

@param key [String, Symbol] @return [String, Symbol]

# File lib/sparkle_formation/translation.rb, line 177
def default_key_format(key)
  key
end
dereference(obj) click to toggle source

Attempt to dereference name

@param obj [Object] @return [Object]

# File lib/sparkle_formation/translation.rb, line 185
def dereference(obj)
  result = obj
  if obj.is_a?(Hash)
    name = obj["Ref"] || obj["get_param"]
    if name
      p_val = parameters[name.to_s]
      if p_val
        result = p_val
      end
    end
  end
  result
end
dereference_processor(obj, funcs = []) click to toggle source

Process object through dereferencer. This will dereference names and apply functions if possible.

@param obj [Object] @return [Object]

# File lib/sparkle_formation/translation.rb, line 217
def dereference_processor(obj, funcs = [])
  case obj
  when Array
    obj = obj.map { |v| dereference_processor(v, funcs) }
  when Hash
    new_hash = {}
    obj.each do |k, v|
      new_hash[k] = dereference_processor(v, funcs)
    end
    obj = apply_function(new_hash, funcs)
  end
  obj
end
format_properties(args) click to toggle source

Format the properties of the new resource

@param args [Hash] @option args [Hash] :original_properties @option args [Hash] :property_map @option args [Hash] :new_resource @option args [Hash] :original_resource @return [Hash]

# File lib/sparkle_formation/translation.rb, line 132
def format_properties(args)
  args[:new_resource]["Properties"] = {}.tap do |new_properties|
    args[:original_properties].each do |property_name, property_value|
      new_key = args[:property_map][property_name]
      if new_key
        if new_key.is_a?(Symbol)
          unless new_key == :delete
            new_key, new_value = send(new_key, property_value,
                                      :new_resource => args[:new_resource],
                                      :new_properties => new_properties,
                                      :original_resource => args[:original_resource])
            new_properties[new_key] = new_value
          end
        else
          new_properties[new_key] = property_value
        end
      else
        logger.warn "Failed to locate property conversion for `#{property_name}` on " \
                    "resource type `#{args[:new_resource]["Type"]}`. Passing directly."
        new_properties[default_key_format(property_name)] = property_value
      end
    end
  end
end
map() click to toggle source

@return [Hash] resource mapping

# File lib/sparkle_formation/translation.rb, line 66
def map
  self.class.const_get(:MAP)
end
mappings() click to toggle source

@return [Hash] mappings for template

# File lib/sparkle_formation/translation.rb, line 51
def mappings
  @original.fetch("Mappings", {})
end
outputs() click to toggle source

@return [Hash] outputs for template

# File lib/sparkle_formation/translation.rb, line 61
def outputs
  @original.fetch("Outputs", {})
end
parameters() click to toggle source

@return [Hash] parameters for template

# File lib/sparkle_formation/translation.rb, line 42
def parameters
  Hash[
    @original.fetch("Parameters", {}).map do |k, v|
      [k, v.fetch("Default", "")]
    end
  ].merge(@parameters)
end
rename_processor(obj, names = []) click to toggle source

Process object through name mapping

@param obj [Object] @param names [Array<Symbol>] enable renaming (:ref, :fn) @return [Object]

# File lib/sparkle_formation/translation.rb, line 236
def rename_processor(obj, names = [])
  case obj
  when Array
    obj = obj.map { |v| rename_processor(v, names) }
  when Hash
    new_hash = {}
    obj.each do |k, v|
      new_hash[k] = rename_processor(v, names)
    end
    obj = apply_rename(new_hash, names)
  end
  obj
end
resource_name(obj) click to toggle source

Provide name of resource

@param obj [Object] @return [String] name

# File lib/sparkle_formation/translation.rb, line 203
def resource_name(obj)
  case obj
  when Hash
    obj["Ref"] || obj["get_resource"]
  else
    obj.to_s
  end
end
resource_translation(resource_name, resource_args) click to toggle source

Translate resource

@param resource_name [String] @param resource_args [Hash] @return [Hash, NilClass] new resource Hash or nil

# File lib/sparkle_formation/translation.rb, line 97
def resource_translation(resource_name, resource_args)
  new_resource = {}
  lookup = map[:resources][resource_args["Type"]]
  if lookup.nil?
    logger.warn "Failed to locate resource type: #{resource_args["Type"]}"
    nil
  elsif lookup == :delete
    logger.warn "Deleting resource #{resource_name} due to configuration"
    nil
  else
    new_resource["Type"] = lookup[:name]
    if resource_args["Properties"]
      new_resource["Properties"] = format_properties(
        :original_properties => resource_args["Properties"],
        :property_map => lookup[:properties],
        :new_resource => new_resource,
        :original_resource => resource_args,
      )
    end
    if lookup[:finalizer]
      send(lookup[:finalizer], resource_name, new_resource, resource_args)
    end
    resource_finalizer(resource_name, new_resource, resource_args)
    new_resource
  end
end
resources() click to toggle source

@return [Hash] resources for template

# File lib/sparkle_formation/translation.rb, line 56
def resources
  @original.fetch("Resources", {})
end
translate!() click to toggle source

Translate stack definition

@return [TrueClass]

# File lib/sparkle_formation/translation.rb, line 73
def translate!
  template.each do |key, value|
    translate_method = "translate_#{snake(key.to_s)}".to_sym
    if respond_to?(translate_method)
      send(translate_method, value)
    else
      translate_default(key, value)
    end
  end
  true
end
translate_default(key, value) click to toggle source

Default translation action if no mapping is provided

@return [Object] value

# File lib/sparkle_formation/translation.rb, line 88
def translate_default(key, value)
  translated[key] = value
end
translate_resources(value) click to toggle source

Translate provided resources

@param value [Hash] resources hash @return [Hash]

# File lib/sparkle_formation/translation.rb, line 161
def translate_resources(value)
  translated["Resources"] = {}
  translated["Resources"].tap do |modified_resources|
    value.each do |resource_name, resource_args|
      new_resource = resource_translation(resource_name, resource_args)
      if new_resource
        modified_resources[resource_name] = new_resource
      end
    end
  end
end