cfhighlander 0.2.0.alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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