Class: Cfhighlander::Model::Component

Inherits:
Object
  • Object
show all
Defined in:
lib/cfhighlander.model.component.rb

Constant Summary collapse

Inline =
'inline'
Substack =
'substack'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(template_meta, component_name, factory) ⇒ Component

Returns a new instance of Component.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/cfhighlander.model.component.rb', line 41

def initialize(template_meta, component_name, factory)
  @template = template_meta
  @name = component_name
  @component_dir = template_meta.template_location
  @mappings = {}
  @version = template_meta.template_version
  @distribution_bucket = nil
  @distribution_prefix = nil
  @component_files = []
  @cfndsl_ext_files = []
  @lambda_src_files = []
  @factory = factory
  @extended_component = nil
  @parent_dsl = nil
  @potential_subcomponent_overrides = {}
  @is_parent_component = false
end

Instance Attribute Details

#cfn_modelObject (readonly)

Returns the value of attribute cfn_model.



33
34
35
# File 'lib/cfhighlander.model.component.rb', line 33

def cfn_model
  @cfn_model
end

#cfn_model_rawObject (readonly)

Returns the value of attribute cfn_model_raw.



33
34
35
# File 'lib/cfhighlander.model.component.rb', line 33

def cfn_model_raw
  @cfn_model_raw
end

#cfndsl_contentObject

Returns the value of attribute cfndsl_content.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def cfndsl_content
  @cfndsl_content
end

#cfndsl_ext_filesObject

Returns the value of attribute cfndsl_ext_files.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def cfndsl_ext_files
  @cfndsl_ext_files
end

#cfndsl_pathObject

Returns the value of attribute cfndsl_path.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def cfndsl_path
  @cfndsl_path
end

#component_dirObject

Returns the value of attribute component_dir.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def component_dir
  @component_dir
end

#component_filesObject

Returns the value of attribute component_files.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def component_files
  @component_files
end

#configObject

Returns the value of attribute config.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def config
  @config
end

#distribution_bucketObject

Returns the value of attribute distribution_bucket.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def distribution_bucket
  @distribution_bucket
end

#distribution_prefixObject

Returns the value of attribute distribution_prefix.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def distribution_prefix
  @distribution_prefix
end

#extended_componentObject

Returns the value of attribute extended_component.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def extended_component
  @extended_component
end

#factoryObject

Returns the value of attribute factory.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def factory
  @factory
end

#highlander_dslObject

Returns the value of attribute highlander_dsl.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def highlander_dsl
  @highlander_dsl
end

#highlander_dsl_pathObject

Returns the value of attribute highlander_dsl_path.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def highlander_dsl_path
  @highlander_dsl_path
end

#is_parent_componentObject

Returns the value of attribute is_parent_component.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def is_parent_component
  @is_parent_component
end

#lambda_src_filesObject

Returns the value of attribute lambda_src_files.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def lambda_src_files
  @lambda_src_files
end

#mappingsObject

Returns the value of attribute mappings.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def mappings
  @mappings
end

#nameObject

Returns the value of attribute name.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def name
  @name
end

#outputsObject (readonly)

Returns the value of attribute outputs.



33
34
35
# File 'lib/cfhighlander.model.component.rb', line 33

def outputs
  @outputs
end

#parent_templateObject

Returns the value of attribute parent_template.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def parent_template
  @parent_template
end

#potential_subcomponent_overridesObject (readonly)

Returns the value of attribute potential_subcomponent_overrides.



33
34
35
# File 'lib/cfhighlander.model.component.rb', line 33

def potential_subcomponent_overrides
  @potential_subcomponent_overrides
end

#templateObject

Returns the value of attribute template.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def template
  @template
end

#template_finderObject

Returns the value of attribute template_finder.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def template_finder
  @template_finder
end

#versionObject

Returns the value of attribute version.



13
14
15
# File 'lib/cfhighlander.model.component.rb', line 13

def version
  @version
end

Instance Method Details

#eval_cfndslObject



252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/cfhighlander.model.component.rb', line 252

def eval_cfndsl
  compiler = Cfhighlander::Compiler::ComponentCompiler.new self
  compiler.lambda_mock_resolve = true
  @cfn_model = compiler.evaluateCloudFormation().as_json
  @cfn_model_raw = JSON.parse(@cfn_model.to_json)
  @outputs = (
  if @cfn_model.key? 'Outputs'
  then
    @cfn_model['Outputs'].map { |k, v| ComponentOutput.new self, k, v }
  else
    []
  end
  )
end

#evaluateHighlanderTemplateObject



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/cfhighlander.model.component.rb', line 226

def evaluateHighlanderTemplate
  loadCfndslContent

  cfhl_script = ''
  @config.each do |key, val|
    cfhl_script += ("\n#{key} = #{val.inspect}\n")
  end
  cfhl_script += File.read(@highlander_dsl_path)
  cfhl_dsl = eval(cfhl_script, binding)
  if not cfhl_dsl.extended_template.nil?
    @parent_template = cfhl_dsl.extended_template
    inheritParentTemplate
    puts "INFO: #{@template} extends #{@parent_template}, loading parent definition..."
    # 2nd pass, template instance is already created from parent
    @highlander_dsl = eval(cfhl_script, binding)
  else
    @highlander_dsl = cfhl_dsl
  end
end

#inheritParentTemplateObject



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/cfhighlander.model.component.rb', line 181

def inheritParentTemplate
  if not @parent_template.nil?
    extended_component = @factory.loadComponentFromTemplate(@parent_template)
    extended_component.is_parent_component = true
    extended_component.load(@config)

    @config = extended_component.config.extend(@config)
    @mappings = extended_component.mappings.extend(@mappings)
    @cfndsl_ext_files += extended_component.cfndsl_ext_files
    @lambda_src_files += extended_component.lambda_src_files
    @extended_component = extended_component

    # extend cfndsl, first comes parent, than child
    # this allows for child component to shadow parent component
    # defined resources. While cfhl evaluation will use parent's template_dir configuration
    # value, for cfndsl, as this is lower level, will resolve in child component template_dir configuration
    # we need to ensure both parent and child components have access to their template_dir variables
    new_template_dir_var = "template_dir_#{SecureRandom.hex[0..8]}"
    extended_component.cfndsl_content.gsub!('template_dir', new_template_dir_var)
    @config[new_template_dir_var] = extended_component.template.template_location
    @cfndsl_content = extended_component.cfndsl_content + @cfndsl_content

    @parent_dsl = extended_component.highlander_dsl

    # in case of hldsl or cfndsl refering to template_dir
  end
end

#load(config_override = nil) ⇒ Object

evaluate components template

Parameters:

  • config_override (Hash) (defaults to: nil)


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/cfhighlander.model.component.rb', line 104

def load(config_override = nil)
  if @component_dir.start_with? 'http'
    raise StandardError, 'http(s) sources not supported yet'
  end

  legacy_cfhighlander_path = "#{@component_dir}/#{@template.template_name}.highlander.rb"
  if File.exist? legacy_cfhighlander_path
    STDERR.puts "DEPRECATED: #{legacy_cfhighlander_path} - Use *.cfhighlander.rb"
    @highlander_dsl_path = legacy_cfhighlander_path
    ENV['CF_COMPONENT_PATH'] = @component_dir
  else
    @highlander_dsl_path = "#{@component_dir}/#{@template.template_name}.cfhighlander.rb"
    ENV['CF_COMPONENT_PATH'] = @component_dir
  end

  @cfndsl_path = "#{@component_dir}/#{@template.template_name}.cfndsl.rb"
  candidate_mappings_path = "#{@component_dir}/*.mappings.yaml"
  candidate_dynamic_mappings_path = "#{@component_dir}/#{@template.template_name}.mappings.rb"

  @cfndsl_ext_files += Dir["#{@component_dir}/ext/cfndsl/*.rb"]
  @lambda_src_files += Dir["#{@component_dir}/lambdas/**/*"].find_all { |p| not File.directory? p }
  @component_files += @cfndsl_ext_files
  @component_files += @lambda_src_files

  @config = {} if @config.nil?

  @config.extend config_override unless config_override.nil?
  @config['component_version'] = @version unless @version.nil?
  @config['component_name'] = @name
  @config['template_name'] = @template.template_name
  @config['template_version'] = @template.template_version
  @config['template_dir'] = @template.template_location
  @config['distribution_bucket'] = @distribution_bucket
  @config['distribution_prefix'] = @distribution_prefix

  Dir[candidate_mappings_path].each do |mapping_file|
    mappings = YAML.load(File.read(mapping_file))
    @component_files << mapping_file
    mappings.each do |name, map|
      @mappings[name] = map
    end unless mappings.nil?
  end

  if File.exist? candidate_dynamic_mappings_path
    require candidate_dynamic_mappings_path
    @component_files << candidate_dynamic_mappings_path
  end

  @component_files << @highlander_dsl_path


  # evaluate template file and load parent if defined
  evaluateHighlanderTemplate

  # set version if not defined
  @highlander_dsl.ComponentVersion(@version) unless @version.nil?


  if @highlander_dsl.description.nil?
    if template.template_name == @name
      description = "#{@name}@#{template.template_version} - v#{@highlander_dsl.version}"
    else
      description = "#{@name} - v#{@highlander_dsl.version}"
      description += " (#{template.template_name}@#{template.template_version})"
    end

    @highlander_dsl.Description(description)
  end unless @is_parent_component

  # set (override) distribution options
  @highlander_dsl.DistributionBucket(@distribution_bucket) unless @distribution_bucket.nil?
  @highlander_dsl.DistributionPrefix(@distribution_prefix) unless @distribution_prefix.nil?


  loadDepandantExt()
end

#load_configObject

load component configuration files



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/cfhighlander.model.component.rb', line 74

def load_config()
  @config = {} if @config.nil?
  Dir["#{@component_dir}/*.config.yaml"].each do |config_file|
    puts "INFO Loading config for #{@name}: read file:#{config_file} "
    partial_config = YAML.load(File.read(config_file), aliases: true)
    if (not partial_config)
      STDERR.puts "WARNING: Configuration file #{config_file} could not be loaded"
      next
    end
    unless (partial_config.nil? or partial_config.key? 'subcomponent_config_file')
      @config.extend(partial_config)
      @component_files << config_file
    end
    fname = File.basename(config_file)
    potential_component_name = fname.gsub('.config.yaml', '')
    @potential_subcomponent_overrides[potential_component_name] = partial_config
  end
end

#loadCfndslContentObject



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/cfhighlander.model.component.rb', line 209

def loadCfndslContent
  if File.exist? @cfndsl_path
    @component_files << @cfndsl_path
    @cfndsl_content = File.read(@cfndsl_path)
    @cfndsl_content.strip!
    # if there is CloudFormation do [content] end extract only contents
    ### Regex \s is whitespace
    match_data = /^CloudFormation do\s(.*)end\s?$/m.match(@cfndsl_content)
    if not match_data.nil?
      @cfndsl_content = match_data[1]
    end

  else
    @cfndsl_content = ''
  end
end

#loadDepandantExtObject

load extensions



94
95
96
97
98
99
100
# File 'lib/cfhighlander.model.component.rb', line 94

def loadDepandantExt()
  @highlander_dsl.dependson_components.each do |requirement|
    requirement.component_loaded.cfndsl_ext_files.each do |file|
      @cfndsl_ext_files << file
    end
  end
end

#set_cfndsl_model(value) ⇒ Object

evaluates cfndsl with current config



247
248
249
250
# File 'lib/cfhighlander.model.component.rb', line 247

def set_cfndsl_model(value)
  @cfn_model = value.as_json
  @cfn_model_raw = JSON.parse(@cfn_model.to_json)
end