Class: SparkleFormation::Translation

Inherits:
Object
  • Object
show all
Includes:
SparkleAttribute, Utils::AnimalStrings
Defined in:
lib/sparkle_formation/translation.rb,
lib/sparkle_formation/translation/heat.rb,
lib/sparkle_formation/translation/rackspace.rb

Overview

Translator

Direct Known Subclasses

Heat

Defined Under Namespace

Classes: Heat, Rackspace

Constant Summary collapse

REF_MAPPING =

Returns mapping for pseudo-parameters.

Returns:

  • (Hash)

    mapping for pseudo-parameters

{}
FN_MAPPING =

Returns mapping for intrinsic functions.

Returns:

  • (Hash)

    mapping for intrinsic functions

{}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SparkleAttribute

#__attribute_key, #_dynamic, #_method, #_nest, #_puts, #_raise, #_registry, #_resource_name, #_system

Methods included from Utils::AnimalStrings

#camel, #snake

Constructor Details

#initialize(template_hash, args = {}) ⇒ Translation

Create new instance

Parameters:

  • template_hash (Hash)

    stack template

  • args (Hash) (defaults to: {})

Options Hash (args):

  • :logger (Logger)

    custom logger

  • :parameters (Hash)

    parameters for stack creation

  • :options (Hash)

    options for translation



33
34
35
36
37
38
39
40
# File 'lib/sparkle_formation/translation.rb', line 33

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

Instance Attribute Details

#loggerLogger (readonly)

Returns current logger.

Returns:

  • (Logger)

    current logger



22
23
24
# File 'lib/sparkle_formation/translation.rb', line 22

def logger
  @logger
end

#optionsHash (readonly)

Returns extra options (generally used by translation implementations).

Returns:

  • (Hash)

    extra options (generally used by translation implementations)



24
25
26
# File 'lib/sparkle_formation/translation.rb', line 24

def options
  @options
end

#originalHash (readonly)

Returns original template.

Returns:

  • (Hash)

    original template



16
17
18
# File 'lib/sparkle_formation/translation.rb', line 16

def original
  @original
end

#templateHash (readonly)

Returns duplicated template (full deep copy).

Returns:

  • (Hash)

    duplicated template (full deep copy)



20
21
22
# File 'lib/sparkle_formation/translation.rb', line 20

def template
  @template
end

#translatedHash (readonly)

Returns current translation.

Returns:

  • (Hash)

    current translation



18
19
20
# File 'lib/sparkle_formation/translation.rb', line 18

def translated
  @translated
end

Instance Method Details

#apply_function(hash, funcs = []) ⇒ Hash

Note:

also allows ‘Ref’ within funcs to provide mapping replacements using the REF_MAPPING constant

Apply function if possible

Parameters:

  • hash (Hash)
  • funcs (Array) (defaults to: [])

    allowed functions

Returns:

  • (Hash)


302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/sparkle_formation/translation.rb', line 302

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 = []) ⇒ Hash

Note:

remapping references to constants: REF_MAPPING for Ref maps FN_MAPPING for Fn maps

Apply function if possible

Parameters:

  • hash (Hash)
  • names (Array<Symbol>) (defaults to: [])

    enable renaming (:ref, :fn)

Returns:

  • (Hash)


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/sparkle_formation/translation.rb', line 260

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) ⇒ Array

Apply ‘GetAttr` mapping if available

Parameters:

  • resource_name (String)
  • value (String)

Returns:

  • (Array)


284
285
286
287
288
289
290
291
292
293
# File 'lib/sparkle_formation/translation.rb', line 284

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) ⇒ String, Symbol

Default formatting for keys

Parameters:

  • key (String, Symbol)

Returns:

  • (String, Symbol)


179
180
181
# File 'lib/sparkle_formation/translation.rb', line 179

def default_key_format(key)
  key
end

#dereference(obj) ⇒ Object

Attempt to dereference name

Parameters:

  • obj (Object)

Returns:

  • (Object)


187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/sparkle_formation/translation.rb', line 187

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 = []) ⇒ Object

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

Parameters:

  • obj (Object)

Returns:

  • (Object)


219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/sparkle_formation/translation.rb', line 219

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) ⇒ Hash

Format the properties of the new resource

Parameters:

  • args (Hash)

Options Hash (args):

  • :original_properties (Hash)
  • :property_map (Hash)
  • :new_resource (Hash)
  • :original_resource (Hash)

Returns:

  • (Hash)


133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/sparkle_formation/translation.rb', line 133

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

#mapHash

Returns resource mapping.

Returns:

  • (Hash)

    resource mapping



67
68
69
# File 'lib/sparkle_formation/translation.rb', line 67

def map
  self.class.const_get(:MAP)
end

#mappingsHash

Returns mappings for template.

Returns:

  • (Hash)

    mappings for template



52
53
54
# File 'lib/sparkle_formation/translation.rb', line 52

def mappings
  @original.fetch('Mappings', {})
end

#outputsHash

Returns outputs for template.

Returns:

  • (Hash)

    outputs for template



62
63
64
# File 'lib/sparkle_formation/translation.rb', line 62

def outputs
  @original.fetch('Outputs', {})
end

#parametersHash

Returns parameters for template.

Returns:

  • (Hash)

    parameters for template



43
44
45
46
47
48
49
# File 'lib/sparkle_formation/translation.rb', line 43

def parameters
  Hash[
    @original.fetch('Parameters', {}).map do |k, v|
      [k, v.fetch('Default', '')]
    end
  ].merge(@parameters)
end

#rename_processor(obj, names = []) ⇒ Object

Process object through name mapping

Parameters:

  • obj (Object)
  • names (Array<Symbol>) (defaults to: [])

    enable renaming (:ref, :fn)

Returns:

  • (Object)


238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/sparkle_formation/translation.rb', line 238

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) ⇒ String

Provide name of resource

Parameters:

  • obj (Object)

Returns:

  • (String)

    name



205
206
207
208
209
210
211
212
# File 'lib/sparkle_formation/translation.rb', line 205

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) ⇒ Hash, NilClass

Translate resource

Parameters:

  • resource_name (String)
  • resource_args (Hash)

Returns:

  • (Hash, NilClass)

    new resource Hash or nil



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/sparkle_formation/translation.rb', line 98

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

#resourcesHash

Returns resources for template.

Returns:

  • (Hash)

    resources for template



57
58
59
# File 'lib/sparkle_formation/translation.rb', line 57

def resources
  @original.fetch('Resources', {})
end

#translate!TrueClass

Translate stack definition

Returns:

  • (TrueClass)


74
75
76
77
78
79
80
81
82
83
84
# File 'lib/sparkle_formation/translation.rb', line 74

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) ⇒ Object

Default translation action if no mapping is provided

Returns:

  • (Object)

    value



89
90
91
# File 'lib/sparkle_formation/translation.rb', line 89

def translate_default(key, value)
  translated[key] = value
end

#translate_resources(value) ⇒ Hash

Translate provided resources

Parameters:

  • value (Hash)

    resources hash

Returns:

  • (Hash)


163
164
165
166
167
168
169
170
171
172
173
# File 'lib/sparkle_formation/translation.rb', line 163

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