cfhighlander 0.2.0.alpha.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,428 @@
1
+ # require all extensions
2
+
3
+ extensions_folder = "#{File.dirname(__FILE__)}/../hl_ext"
4
+
5
+ Dir["#{extensions_folder}/*.rb"].each { |f|
6
+ require f
7
+ }
8
+
9
+ # require libraries
10
+
11
+ require_relative './highlander.dsl.base'
12
+ require_relative './highlander.dsl.params'
13
+ require_relative './highlander.dsl.component'
14
+
15
+ module Highlander
16
+
17
+ module Dsl
18
+
19
+ class Template < DslBase
20
+
21
+ attr_accessor :mappings,
22
+ :parameters,
23
+ :name,
24
+ :components,
25
+ :version,
26
+ :distribute_url,
27
+ :distribution_bucket,
28
+ :distribution_prefix,
29
+ :lambda_functions_keys,
30
+ :description,
31
+ :dependson_components
32
+
33
+ def initialize
34
+ @mappings = []
35
+ @components = []
36
+ @config = { 'mappings' => {}, 'component_version' => 'latest' }
37
+ @component_configs = {}
38
+ @version = 'latest'
39
+ @distribute_url = nil
40
+ @distribution_prefix = ''
41
+ @component_sources = []
42
+ @parameters = Parameters.new
43
+ @lambda_functions_keys = []
44
+ @dependson_components_templates = []
45
+ @dependson_components = []
46
+ end
47
+
48
+ # DSL statements
49
+
50
+ def addMapping(name, map)
51
+ @mappings << name
52
+ @config['mappings'] = {} unless @config.key?('mappings')
53
+ @config['mappings'][name] = map
54
+ end
55
+
56
+ def Name(name)
57
+ @name = name
58
+ @config['component_name'] = name
59
+ end
60
+
61
+ def Description(description)
62
+ @description = description
63
+ @config['description'] = description
64
+ end
65
+
66
+ def Parameters(&block)
67
+ @parameters.config = @config
68
+ @parameters.instance_eval(&block)
69
+ end
70
+
71
+ def DynamicMappings(providerName)
72
+ maps = mappings_provider_maps(providerName, self.config)
73
+ maps.each { |name, map| addMapping(name, map) } unless maps.nil?
74
+ end
75
+
76
+ def DependsOn(template)
77
+ @dependson_components_templates << template
78
+ end
79
+
80
+
81
+ def Component(name:, template:, param_values: {}, config: {}, export_config: {}, &block)
82
+ puts "Initialize #{name} with template #{template}"
83
+
84
+ # load component
85
+ component = Highlander::Dsl::Component.new(self,
86
+ name,
87
+ template,
88
+ param_values,
89
+ @component_sources,
90
+ config,
91
+ export_config
92
+ )
93
+ component.distribute_bucket = @distribution_bucket unless @distribution_bucket.nil?
94
+ component.distribute_prefix = @distribution_prefix unless @distribution_prefix.nil?
95
+ component.version = @version unless @version.nil?
96
+ @component_configs[name] = config
97
+ @components << component
98
+ end
99
+
100
+ def ComponentVersion(version)
101
+ @version = version
102
+ @config['component_version'] = version
103
+ build_distribution_url
104
+ end
105
+
106
+ def DistributionPrefix(prefix)
107
+ @distribution_prefix = prefix
108
+ build_distribution_url
109
+ end
110
+
111
+ def DistributionBucket(bucket_name)
112
+ @distribution_bucket = bucket_name
113
+ build_distribution_url
114
+ end
115
+
116
+ def ComponentDistribution(s3_url)
117
+ if s3_url.start_with? 's3://'
118
+ if s3_url.split('/').length < 4
119
+ raise 'Unrecognised distribution url, only supporting s3://bucket/prefix urls'
120
+ end
121
+ parts = s3_url.split('/')
122
+ @distribution_bucket = parts[2]
123
+ @distribution_prefix = parts[3]
124
+ i = 4
125
+ while i < parts.size()
126
+ @distribution_prefix += "/#{parts[i]}"
127
+ i += 1
128
+ end
129
+ @distribution_prefix = @distribution_prefix.chomp('/')
130
+
131
+ build_distribution_url
132
+ else
133
+ raise 'Unrecognised distribution url, only supporting s3://bucket/prefix urls'
134
+ end
135
+ end
136
+
137
+ def ComponentSources(sources_array)
138
+ @component_sources = sources_array
139
+ end
140
+
141
+ def LambdaFunctions(config_key)
142
+ @lambda_functions_keys << config_key
143
+ end
144
+
145
+ # Internal and interface functions
146
+
147
+ def loadComponents()
148
+
149
+ # empty config overrides to start with
150
+ @config_overrides = Hash[@components.collect { |c| [c.name, {}] }]
151
+ @named_components = Hash[@components.collect { |c| [c.name, c] }]
152
+
153
+ # populate overrides with master config defined overrides
154
+ load_configfile_component_config
155
+
156
+ # populate overrides with config defined explictily
157
+ load_explicit_component_config
158
+
159
+ # apply configuration exports
160
+ apply_config_overrides
161
+ apply_config_exports
162
+
163
+
164
+ # component exports may have overriden some of explicit / configfile configuration, reapply
165
+ load_configfile_component_config
166
+ load_explicit_component_config
167
+
168
+ # apply extension exports
169
+ load_extension_exports
170
+
171
+
172
+ # load components and extract parent stack parameters and mappings
173
+ @components.each { |component|
174
+
175
+ component.load @config_overrides[component.name]
176
+ # add all of it's stack parameters unless same template has been already processed
177
+ component
178
+ .component_loaded
179
+ .highlander_dsl
180
+ .parameters
181
+ .param_list.each do |param|
182
+
183
+ # add stack parameters
184
+ if param.class == Highlander::Dsl::StackParam
185
+ # sub-component stack param becomes top-level component param
186
+ param_name = param.is_global ? param.name : "#{component.name}#{param.name}"
187
+ stack_param = Highlander::Dsl::ComponentParam.new(
188
+ param_name,
189
+ param.type,
190
+ param.default_value,
191
+ param.no_echo
192
+ )
193
+ @parameters.addParam stack_param
194
+ end unless component.param_values.key? param.name
195
+
196
+ # for map parameters add maps
197
+ if param.class == Highlander::Dsl::MappingParam
198
+ if not param.mapProvider.nil?
199
+ maps = param.mapProvider.getMaps(component.component_loaded.config)
200
+ maps.each do |name, map|
201
+ if not @mappings.include? name
202
+ #1. add mapping name to model
203
+ @mappings << name
204
+ #2. add mapping to config to be rendered via cfndsl
205
+ @config['mappings'] = {} if @config['mappings'].nil?
206
+ @config['mappings'][name] = map
207
+ end
208
+ end unless maps.nil?
209
+ end
210
+ end
211
+
212
+ end
213
+
214
+ # late bind parameter values, once mappings and top level params are extracted
215
+ component.load_parameters
216
+ }
217
+
218
+ @dependson_components_templates.each do |template|
219
+ component = Highlander::Dsl::Component.new(self,
220
+ template,
221
+ template,
222
+ {},
223
+ @component_sources
224
+ )
225
+ component.load
226
+ @dependson_components << component
227
+ end
228
+ end
229
+
230
+ def load_extension_exports
231
+ @components.each do |c|
232
+ component = c.component_loaded
233
+ config = component.config
234
+ if ((config.key? 'lib_export') and (config['lib_export'].key? 'global'))
235
+
236
+ global_export_config = config['lib_export']['global']
237
+ if global_export_config.key? 'cfndsl'
238
+ global_export_config['cfndsl'].each do |exported_extension|
239
+ extension_file_path = "#{component.component_dir}/ext/cfndsl/#{exported_extension}.rb"
240
+ @components.each do |cr|
241
+ cr.component_loaded.cfndsl_ext_files << extension_file_path unless cr == c
242
+ end
243
+ end
244
+ end
245
+
246
+ end
247
+ end
248
+ end
249
+
250
+ def apply_config_overrides
251
+ @config_overrides.each { |component_name, component_override|
252
+ @named_components[component_name].component_loaded.config.extend(component_override)
253
+ }
254
+ end
255
+
256
+ def load_configfile_component_config
257
+ if (@config.key? 'components')
258
+ @config['components'].each { |component_name, component_config|
259
+ if component_config.key?('config')
260
+ @config_overrides[component_name].extend(component_config['config'])
261
+ end
262
+ }
263
+ end
264
+ end
265
+
266
+ def apply_config_exports
267
+ # first export from master to all children
268
+ if ((@config.key? 'config_export') and (@config['config_export']['global']))
269
+ @config['config_export']['global'].each { |global_export_key|
270
+ if @config.key? global_export_key
271
+ @config_overrides.each { |cname, co|
272
+ co[global_export_key] = @config[global_export_key]
273
+ }
274
+ end
275
+ }
276
+ end
277
+
278
+ @components.each { |component|
279
+ cl = component.component_loaded
280
+ if ((not cl.config.nil?) and (cl.config.key? 'config_export'))
281
+
282
+ # global config
283
+ if cl.config['config_export'].key? 'global'
284
+ cl.config['config_export']['global'].each { |global_export_key|
285
+
286
+ # global config is exported to parent and every component
287
+ if cl.config.key? global_export_key
288
+
289
+ # cname is for component name, co for component override
290
+ @config_overrides.each { |cname, co|
291
+
292
+ # if templates are different e.g don't export from vpc to vpc
293
+ config_receiver_component = @named_components[cname]
294
+ if config_receiver_component.template != component.template
295
+ if (not config_receiver_component.export_config.nil?) and (config_receiver_component.export_config.key? component.template)
296
+ allow_from_component_name = config_receiver_component.export_config[component.template]
297
+ if allow_from_component_name == component.name
298
+ puts("Exporting key #{global_export_key} from component #{component.name} to #{cname}")
299
+ co[global_export_key] = cl.config[global_export_key]
300
+ end
301
+ else
302
+ puts("Exporting key #{global_export_key} from component #{component.name} to #{cname}")
303
+ co[global_export_key] = cl.config[global_export_key]
304
+ end
305
+ end
306
+ }
307
+
308
+
309
+ else
310
+ STDERR.puts("Trying to export non-existent configuration key #{global_export_key}")
311
+ end
312
+ }
313
+ end
314
+
315
+ if cl.config['config_export'].key? 'component'
316
+ cl.config['config_export']['component'].each { |component_name, export_keys|
317
+ # check if there is configuration of export from this component
318
+ # and if there is export configuration for given component name
319
+
320
+ if (not component.export_config.nil?) and (component.export_config.key? component_name)
321
+ # if there is component with such name
322
+ if @config_overrides.key? component.export_config[component_name]
323
+ # override the config
324
+ real_component_name = component.export_config[component_name]
325
+ export_keys.each { |export_component_key|
326
+ puts("Exporting config for key=#{export_component_key} from #{component.name} to #{real_component_name}")
327
+ if not @config_overrides[real_component_name].key? export_component_key
328
+ @config_overrides[real_component_name][export_component_key] = {}
329
+ end
330
+ @config_overrides[real_component_name][export_component_key].extend(cl.config[export_component_key])
331
+ }
332
+ else
333
+ STDERR.puts("Trying to export configuration for non-existant component #{component.export_config[component_name]}")
334
+ end
335
+ elsif @config_overrides.key? component_name
336
+ export_keys.each { |export_component_key|
337
+ puts("Exporting config for key=#{export_component_key} from #{component.name} to #{component_name}")
338
+ if not @config_overrides[component_name].key? export_component_key
339
+ @config_overrides[component_name][export_component_key] = {}
340
+ end
341
+ @config_overrides[component_name][export_component_key].extend(cl.config[export_component_key])
342
+ }
343
+ else
344
+ STDERR.puts("Trying to export configuration for non-existant component #{component_name}")
345
+ end
346
+ }
347
+ end
348
+ # component config
349
+ # loop over keys
350
+ # check if there
351
+ end
352
+ }
353
+ end
354
+
355
+ def load_explicit_component_config
356
+ @component_configs.each { |component_name, component_config|
357
+ @config_overrides[component_name].extend(component_config)
358
+ }
359
+ end
360
+
361
+ def distribute_bucket=(value)
362
+ @distribution_bucket = value
363
+ build_distribution_url
364
+ end
365
+
366
+ def distribute_prefix=(value)
367
+ @distribution_prefix = value
368
+ build_distribution_url
369
+ end
370
+
371
+ def name=(value)
372
+ self.Name(value)
373
+ end
374
+
375
+ def build_distribution_url
376
+ if not (@distribution_bucket.nil? or @distribution_prefix.nil?)
377
+ @distribute_url = "https://#{@distribution_bucket}.s3.amazonaws.com/#{@distribution_prefix}"
378
+ @distribute_url = "#{@distribute_url}/#{@version}" unless @version.nil?
379
+ @components.each { |component|
380
+ component.distribute_bucket = @distribution_bucket unless @distribution_bucket.nil?
381
+ component.distribute_prefix = @distribution_prefix unless @distribution_prefix.nil?
382
+ component.version = @version unless @version.nil?
383
+ component.build_distribution_url
384
+ }
385
+ end
386
+ end
387
+
388
+
389
+ end
390
+ end
391
+
392
+ end
393
+
394
+ def HighlanderComponent(&block)
395
+ instance = Highlander::Dsl::Template.new
396
+
397
+ puts "Processing higlander component #{@name}\n\tLocation:#{@highlander_dsl_path}" +
398
+ "\n\tConfig:#{@config}"
399
+
400
+ component_config = @config
401
+
402
+ instance.config = @config
403
+
404
+ @mappings.each do |key, val|
405
+ instance.addMapping(key, val)
406
+ end
407
+
408
+ unless @version.nil?
409
+ instance.version = @version
410
+ end
411
+
412
+ unless @distribution_bucket.nil?
413
+ instance.DistributionBucket(@distribution_bucket)
414
+ end
415
+ unless @distribution_prefix.nil?
416
+ instance.DistributionPrefix(@distribution_prefix)
417
+ end
418
+
419
+ instance.instance_eval(&block)
420
+ if instance.name.nil?
421
+ instance.name = @name
422
+ end
423
+
424
+ # load sub-components
425
+ instance.loadComponents
426
+
427
+ return instance
428
+ end