cfhighlander 0.2.1.alpha.43 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +79 -153
- data/bin/cfhighlander +1 -1
- data/bin/{cfhighlander.rb → highlander.rb} +22 -27
- data/cfndsl_ext/sg.rb +2 -29
- data/hl_ext/mapping_helper.rb +4 -6
- data/lib/{cfhighlander.compiler.rb → highlander.compiler.rb} +18 -26
- data/lib/{cfhighlander.dsl.base.rb → highlander.dsl.base.rb} +2 -2
- data/lib/{cfhighlander.dsl.subcomponent.rb → highlander.dsl.component.rb} +71 -83
- data/lib/highlander.dsl.params.rb +113 -0
- data/lib/{cfhighlander.dsl.template.rb → highlander.dsl.rb} +62 -91
- data/lib/highlander.factory.rb +359 -0
- data/lib/{cfhighlander.helper.rb → highlander.helper.rb} +2 -2
- data/lib/{cfhighlander.mapproviders.rb → highlander.mapproviders.rb} +1 -1
- data/lib/{cfhighlander.publisher.rb → highlander.publisher.rb} +3 -3
- data/lib/{cfhighlander.validator.rb → highlander.validator.rb} +1 -1
- data/lib/util/zip.util.rb +1 -1
- data/templates/cfndsl.component.template.erb +1 -4
- metadata +15 -38
- data/lib/cfhighlander.dsl.params.rb +0 -108
- data/lib/cfhighlander.factory.rb +0 -45
- data/lib/cfhighlander.factory.templatefinder.rb +0 -248
- data/lib/cfhighlander.model.component.rb +0 -177
- data/lib/cfhighlander.model.templatemeta.rb +0 -25
@@ -2,26 +2,26 @@
|
|
2
2
|
|
3
3
|
extensions_folder = "#{File.dirname(__FILE__)}/../hl_ext"
|
4
4
|
|
5
|
-
Dir["#{extensions_folder}/*.rb"].each {|f|
|
5
|
+
Dir["#{extensions_folder}/*.rb"].each { |f|
|
6
6
|
require f
|
7
7
|
}
|
8
8
|
|
9
9
|
# require libraries
|
10
10
|
|
11
|
-
require_relative './
|
12
|
-
require_relative './
|
13
|
-
require_relative './
|
11
|
+
require_relative './highlander.dsl.base'
|
12
|
+
require_relative './highlander.dsl.params'
|
13
|
+
require_relative './highlander.dsl.component'
|
14
14
|
|
15
|
-
module
|
15
|
+
module Highlander
|
16
16
|
|
17
17
|
module Dsl
|
18
18
|
|
19
|
-
class
|
19
|
+
class Template < DslBase
|
20
20
|
|
21
21
|
attr_accessor :mappings,
|
22
22
|
:parameters,
|
23
23
|
:name,
|
24
|
-
:
|
24
|
+
:components,
|
25
25
|
:version,
|
26
26
|
:distribute_url,
|
27
27
|
:distribution_bucket,
|
@@ -32,7 +32,7 @@ module Cfhighlander
|
|
32
32
|
|
33
33
|
def initialize
|
34
34
|
@mappings = []
|
35
|
-
@
|
35
|
+
@components = []
|
36
36
|
@config = { 'mappings' => {}, 'component_version' => 'latest' }
|
37
37
|
@component_configs = {}
|
38
38
|
@version = 'latest'
|
@@ -54,12 +54,8 @@ module Cfhighlander
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def Name(name)
|
57
|
-
|
58
|
-
|
59
|
-
if (not @config.key? 'nested_component')
|
60
|
-
@name = name
|
61
|
-
@config['component_name'] = name
|
62
|
-
end
|
57
|
+
@name = name
|
58
|
+
@config['component_name'] = name
|
63
59
|
end
|
64
60
|
|
65
61
|
def Description(description)
|
@@ -74,7 +70,7 @@ module Cfhighlander
|
|
74
70
|
|
75
71
|
def DynamicMappings(providerName)
|
76
72
|
maps = mappings_provider_maps(providerName, self.config)
|
77
|
-
maps.each {|name, map| addMapping(name, map)} unless maps.nil?
|
73
|
+
maps.each { |name, map| addMapping(name, map) } unless maps.nil?
|
78
74
|
end
|
79
75
|
|
80
76
|
def DependsOn(template)
|
@@ -82,23 +78,11 @@ module Cfhighlander
|
|
82
78
|
end
|
83
79
|
|
84
80
|
|
85
|
-
def Component(
|
86
|
-
|
87
|
-
param_values: {},
|
88
|
-
config: {},
|
89
|
-
export_config: {}, &block)
|
90
|
-
puts "INFO: Requested subcomponent #{name} with template #{template}"
|
91
|
-
if ((not template_arg.nil?) and template.nil?)
|
92
|
-
template = template_arg
|
93
|
-
elsif (template_arg.nil? and template.nil?)
|
94
|
-
raise 'Component must be defined with template name at minimum,' +
|
95
|
-
' passed as first argument, or template: named arguent'
|
96
|
-
end
|
97
|
-
|
98
|
-
name = template if name.nil?
|
81
|
+
def Component(name:, template:, param_values: {}, config: {}, export_config: {}, &block)
|
82
|
+
puts "Initialize #{name} with template #{template}"
|
99
83
|
|
100
84
|
# load component
|
101
|
-
component =
|
85
|
+
component = Highlander::Dsl::Component.new(self,
|
102
86
|
name,
|
103
87
|
template,
|
104
88
|
param_values,
|
@@ -106,12 +90,11 @@ module Cfhighlander
|
|
106
90
|
config,
|
107
91
|
export_config
|
108
92
|
)
|
109
|
-
component.instance_eval(&block) unless block.nil?
|
110
93
|
component.distribute_bucket = @distribution_bucket unless @distribution_bucket.nil?
|
111
94
|
component.distribute_prefix = @distribution_prefix unless @distribution_prefix.nil?
|
112
95
|
component.version = @version unless @version.nil?
|
113
96
|
@component_configs[name] = config
|
114
|
-
@
|
97
|
+
@components << component
|
115
98
|
end
|
116
99
|
|
117
100
|
def ComponentVersion(version)
|
@@ -164,8 +147,8 @@ module Cfhighlander
|
|
164
147
|
def loadComponents()
|
165
148
|
|
166
149
|
# empty config overrides to start with
|
167
|
-
@config_overrides = Hash[@
|
168
|
-
@named_components = Hash[@
|
150
|
+
@config_overrides = Hash[@components.collect { |c| [c.name, {}] }]
|
151
|
+
@named_components = Hash[@components.collect { |c| [c.name, c] }]
|
169
152
|
|
170
153
|
# populate overrides with master config defined overrides
|
171
154
|
load_configfile_component_config
|
@@ -187,7 +170,7 @@ module Cfhighlander
|
|
187
170
|
|
188
171
|
|
189
172
|
# load components and extract parent stack parameters and mappings
|
190
|
-
@
|
173
|
+
@components.each { |component|
|
191
174
|
|
192
175
|
component.load @config_overrides[component.name]
|
193
176
|
# add all of it's stack parameters unless same template has been already processed
|
@@ -197,8 +180,21 @@ module Cfhighlander
|
|
197
180
|
.parameters
|
198
181
|
.param_list.each do |param|
|
199
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
|
+
|
200
196
|
# for map parameters add maps
|
201
|
-
if param.class ==
|
197
|
+
if param.class == Highlander::Dsl::MappingParam
|
202
198
|
if not param.mapProvider.nil?
|
203
199
|
maps = param.mapProvider.getMaps(component.component_loaded.config)
|
204
200
|
maps.each do |name, map|
|
@@ -215,24 +211,12 @@ module Cfhighlander
|
|
215
211
|
|
216
212
|
end
|
217
213
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
# in 2nd pass, load parameters
|
222
|
-
# 2nd pass is required as all of cfndsl models need to be populated
|
223
|
-
available_outputs = {}
|
224
|
-
@subcomponents.each do |c|
|
225
|
-
c.component_loaded.outputs.each do |out|
|
226
|
-
available_outputs[out.name] = out
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
@subcomponents.each do |component|
|
231
|
-
component.resolve_parameter_values available_outputs
|
232
|
-
end
|
214
|
+
# late bind parameter values, once mappings and top level params are extracted
|
215
|
+
component.load_parameters
|
216
|
+
}
|
233
217
|
|
234
218
|
@dependson_components_templates.each do |template|
|
235
|
-
component =
|
219
|
+
component = Highlander::Dsl::Component.new(self,
|
236
220
|
template,
|
237
221
|
template,
|
238
222
|
{},
|
@@ -244,7 +228,7 @@ module Cfhighlander
|
|
244
228
|
end
|
245
229
|
|
246
230
|
def load_extension_exports
|
247
|
-
@
|
231
|
+
@components.each do |c|
|
248
232
|
component = c.component_loaded
|
249
233
|
config = component.config
|
250
234
|
if ((config.key? 'lib_export') and (config['lib_export'].key? 'global'))
|
@@ -253,7 +237,7 @@ module Cfhighlander
|
|
253
237
|
if global_export_config.key? 'cfndsl'
|
254
238
|
global_export_config['cfndsl'].each do |exported_extension|
|
255
239
|
extension_file_path = "#{component.component_dir}/ext/cfndsl/#{exported_extension}.rb"
|
256
|
-
@
|
240
|
+
@components.each do |cr|
|
257
241
|
cr.component_loaded.cfndsl_ext_files << extension_file_path unless cr == c
|
258
242
|
end
|
259
243
|
end
|
@@ -264,20 +248,16 @@ module Cfhighlander
|
|
264
248
|
end
|
265
249
|
|
266
250
|
def apply_config_overrides
|
267
|
-
@config_overrides.each {|component_name, component_override|
|
251
|
+
@config_overrides.each { |component_name, component_override|
|
268
252
|
@named_components[component_name].component_loaded.config.extend(component_override)
|
269
253
|
}
|
270
254
|
end
|
271
255
|
|
272
256
|
def load_configfile_component_config
|
273
257
|
if (@config.key? 'components')
|
274
|
-
@config['components'].each {|component_name, component_config|
|
258
|
+
@config['components'].each { |component_name, component_config|
|
275
259
|
if component_config.key?('config')
|
276
|
-
|
277
|
-
@config_overrides[component_name].extend(component_config['config'])
|
278
|
-
else
|
279
|
-
STDERR.puts("WARN: Overriding config for non-existing component #{component_name}")
|
280
|
-
end
|
260
|
+
@config_overrides[component_name].extend(component_config['config'])
|
281
261
|
end
|
282
262
|
}
|
283
263
|
end
|
@@ -286,28 +266,28 @@ module Cfhighlander
|
|
286
266
|
def apply_config_exports
|
287
267
|
# first export from master to all children
|
288
268
|
if ((@config.key? 'config_export') and (@config['config_export']['global']))
|
289
|
-
@config['config_export']['global'].each {|global_export_key|
|
269
|
+
@config['config_export']['global'].each { |global_export_key|
|
290
270
|
if @config.key? global_export_key
|
291
|
-
@config_overrides.each {|cname, co|
|
271
|
+
@config_overrides.each { |cname, co|
|
292
272
|
co[global_export_key] = @config[global_export_key]
|
293
273
|
}
|
294
274
|
end
|
295
275
|
}
|
296
276
|
end
|
297
277
|
|
298
|
-
@
|
278
|
+
@components.each { |component|
|
299
279
|
cl = component.component_loaded
|
300
280
|
if ((not cl.config.nil?) and (cl.config.key? 'config_export'))
|
301
281
|
|
302
282
|
# global config
|
303
283
|
if cl.config['config_export'].key? 'global'
|
304
|
-
cl.config['config_export']['global'].each {|global_export_key|
|
284
|
+
cl.config['config_export']['global'].each { |global_export_key|
|
305
285
|
|
306
286
|
# global config is exported to parent and every component
|
307
287
|
if cl.config.key? global_export_key
|
308
288
|
|
309
289
|
# cname is for component name, co for component override
|
310
|
-
@config_overrides.each {|cname, co|
|
290
|
+
@config_overrides.each { |cname, co|
|
311
291
|
|
312
292
|
# if templates are different e.g don't export from vpc to vpc
|
313
293
|
config_receiver_component = @named_components[cname]
|
@@ -315,11 +295,11 @@ module Cfhighlander
|
|
315
295
|
if (not config_receiver_component.export_config.nil?) and (config_receiver_component.export_config.key? component.template)
|
316
296
|
allow_from_component_name = config_receiver_component.export_config[component.template]
|
317
297
|
if allow_from_component_name == component.name
|
318
|
-
puts("
|
298
|
+
puts("Exporting key #{global_export_key} from component #{component.name} to #{cname}")
|
319
299
|
co[global_export_key] = cl.config[global_export_key]
|
320
300
|
end
|
321
301
|
else
|
322
|
-
puts("
|
302
|
+
puts("Exporting key #{global_export_key} from component #{component.name} to #{cname}")
|
323
303
|
co[global_export_key] = cl.config[global_export_key]
|
324
304
|
end
|
325
305
|
end
|
@@ -333,7 +313,7 @@ module Cfhighlander
|
|
333
313
|
end
|
334
314
|
|
335
315
|
if cl.config['config_export'].key? 'component'
|
336
|
-
cl.config['config_export']['component'].each {|component_name, export_keys|
|
316
|
+
cl.config['config_export']['component'].each { |component_name, export_keys|
|
337
317
|
# check if there is configuration of export from this component
|
338
318
|
# and if there is export configuration for given component name
|
339
319
|
|
@@ -342,7 +322,7 @@ module Cfhighlander
|
|
342
322
|
if @config_overrides.key? component.export_config[component_name]
|
343
323
|
# override the config
|
344
324
|
real_component_name = component.export_config[component_name]
|
345
|
-
export_keys.each {|export_component_key|
|
325
|
+
export_keys.each { |export_component_key|
|
346
326
|
puts("Exporting config for key=#{export_component_key} from #{component.name} to #{real_component_name}")
|
347
327
|
if not @config_overrides[real_component_name].key? export_component_key
|
348
328
|
@config_overrides[real_component_name][export_component_key] = {}
|
@@ -353,7 +333,7 @@ module Cfhighlander
|
|
353
333
|
STDERR.puts("Trying to export configuration for non-existant component #{component.export_config[component_name]}")
|
354
334
|
end
|
355
335
|
elsif @config_overrides.key? component_name
|
356
|
-
export_keys.each {|export_component_key|
|
336
|
+
export_keys.each { |export_component_key|
|
357
337
|
puts("Exporting config for key=#{export_component_key} from #{component.name} to #{component_name}")
|
358
338
|
if not @config_overrides[component_name].key? export_component_key
|
359
339
|
@config_overrides[component_name][export_component_key] = {}
|
@@ -373,7 +353,7 @@ module Cfhighlander
|
|
373
353
|
end
|
374
354
|
|
375
355
|
def load_explicit_component_config
|
376
|
-
@component_configs.each {|component_name, component_config|
|
356
|
+
@component_configs.each { |component_name, component_config|
|
377
357
|
@config_overrides[component_name].extend(component_config)
|
378
358
|
}
|
379
359
|
end
|
@@ -388,15 +368,15 @@ module Cfhighlander
|
|
388
368
|
build_distribution_url
|
389
369
|
end
|
390
370
|
|
391
|
-
|
392
|
-
|
393
|
-
|
371
|
+
def name=(value)
|
372
|
+
self.Name(value)
|
373
|
+
end
|
394
374
|
|
395
375
|
def build_distribution_url
|
396
376
|
if not (@distribution_bucket.nil? or @distribution_prefix.nil?)
|
397
377
|
@distribute_url = "https://#{@distribution_bucket}.s3.amazonaws.com/#{@distribution_prefix}"
|
398
378
|
@distribute_url = "#{@distribute_url}/#{@version}" unless @version.nil?
|
399
|
-
@
|
379
|
+
@components.each { |component|
|
400
380
|
component.distribute_bucket = @distribution_bucket unless @distribution_bucket.nil?
|
401
381
|
component.distribute_prefix = @distribution_prefix unless @distribution_prefix.nil?
|
402
382
|
component.version = @version unless @version.nil?
|
@@ -411,12 +391,13 @@ module Cfhighlander
|
|
411
391
|
|
412
392
|
end
|
413
393
|
|
414
|
-
def
|
415
|
-
instance =
|
394
|
+
def HighlanderComponent(&block)
|
395
|
+
instance = Highlander::Dsl::Template.new
|
416
396
|
|
417
397
|
puts "Processing higlander component #{@name}\n\tLocation:#{@highlander_dsl_path}" +
|
418
398
|
"\n\tConfig:#{@config}"
|
419
399
|
|
400
|
+
component_config = @config
|
420
401
|
|
421
402
|
instance.config = @config
|
422
403
|
|
@@ -426,7 +407,6 @@ def CfhighlanderTemplate(&block)
|
|
426
407
|
|
427
408
|
unless @version.nil?
|
428
409
|
instance.version = @version
|
429
|
-
instance.config['component_version'] = @version
|
430
410
|
end
|
431
411
|
|
432
412
|
unless @distribution_bucket.nil?
|
@@ -436,22 +416,13 @@ def CfhighlanderTemplate(&block)
|
|
436
416
|
instance.DistributionPrefix(@distribution_prefix)
|
437
417
|
end
|
438
418
|
|
439
|
-
instance.name = @template.template_name
|
440
419
|
instance.instance_eval(&block)
|
441
|
-
|
420
|
+
if instance.name.nil?
|
421
|
+
instance.name = @name
|
422
|
+
end
|
442
423
|
|
443
424
|
# load sub-components
|
444
425
|
instance.loadComponents
|
445
426
|
|
446
427
|
return instance
|
447
428
|
end
|
448
|
-
|
449
|
-
def CfhighlanderComponent(&block)
|
450
|
-
STDERR.puts("DEPRECATED: #{@template.template_name}: use CfhighlanderTemplate instead of CfhighlanderComponent")
|
451
|
-
CfhighlanderTemplate(&block)
|
452
|
-
end
|
453
|
-
|
454
|
-
def HighlanderComponent(&block)
|
455
|
-
STDERR.puts("DEPRECATED: #{@template.template_name}: use CfhighlanderTemplate instead of HighlanderComponent")
|
456
|
-
CfhighlanderTemplate(&block)
|
457
|
-
end
|
@@ -0,0 +1,359 @@
|
|
1
|
+
require_relative './highlander.dsl'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'git'
|
4
|
+
|
5
|
+
LOCAL_HIGHLANDER_CACHE_LOCATION = "#{ENV['HOME']}/.highlander/components"
|
6
|
+
|
7
|
+
module Highlander
|
8
|
+
|
9
|
+
module Factory
|
10
|
+
|
11
|
+
class Component
|
12
|
+
|
13
|
+
attr_accessor :component_dir,
|
14
|
+
:config,
|
15
|
+
:highlander_dsl_path,
|
16
|
+
:cfndsl_path,
|
17
|
+
:highlander_dsl,
|
18
|
+
:cfndsl_content,
|
19
|
+
:mappings,
|
20
|
+
:name,
|
21
|
+
:version,
|
22
|
+
:distribution_bucket,
|
23
|
+
:distribution_prefix,
|
24
|
+
:component_files,
|
25
|
+
:cfndsl_ext_files,
|
26
|
+
:lambda_src_files
|
27
|
+
|
28
|
+
def initialize(component_name, component_dir)
|
29
|
+
@name = component_name
|
30
|
+
@component_dir = component_dir
|
31
|
+
@mappings = {}
|
32
|
+
@version = nil
|
33
|
+
@distribution_bucket = nil
|
34
|
+
@distribution_prefix = nil
|
35
|
+
@component_files = []
|
36
|
+
@cfndsl_ext_files = []
|
37
|
+
@lambda_src_files = []
|
38
|
+
end
|
39
|
+
|
40
|
+
def load_config()
|
41
|
+
@config = {} if @config.nil?
|
42
|
+
Dir["#{@component_dir}/*.config.yaml"].each do |config_file|
|
43
|
+
partial_config = YAML.load(File.read(config_file))
|
44
|
+
unless partial_config.nil?
|
45
|
+
@config.extend(partial_config)
|
46
|
+
@component_files << config_file
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def loadDepandantExt()
|
53
|
+
@highlander_dsl.dependson_components.each do |requirement|
|
54
|
+
requirement.component_loaded.cfndsl_ext_files.each do |file|
|
55
|
+
cfndsl_ext_files << file
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param [Hash] config_override
|
61
|
+
def load(config_override = nil)
|
62
|
+
if @component_dir.start_with? 'http'
|
63
|
+
raise StandardError, 'http(s) sources not supported yet'
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
@highlander_dsl_path = "#{@component_dir}/#{@name}.highlander.rb"
|
68
|
+
@cfndsl_path = "#{@component_dir}/#{@name}.cfndsl.rb"
|
69
|
+
candidate_config_path = "#{@component_dir}/#{@name}.config.yaml"
|
70
|
+
candidate_mappings_path = "#{@component_dir}/*.mappings.yaml"
|
71
|
+
candidate_dynamic_mappings_path = "#{@component_dir}/#{@name}.mappings.rb"
|
72
|
+
|
73
|
+
@cfndsl_ext_files += Dir["#{@component_dir}/ext/cfndsl/*.rb"]
|
74
|
+
@lambda_src_files += Dir["#{@component_dir}/lambdas/**/*"].find_all {|p| not File.directory? p}
|
75
|
+
@component_files += @cfndsl_ext_files
|
76
|
+
@component_files += @lambda_src_files
|
77
|
+
|
78
|
+
@config = {} if @config.nil?
|
79
|
+
|
80
|
+
@config.extend config_override unless config_override.nil?
|
81
|
+
@config['component_version'] = @version unless @version.nil?
|
82
|
+
# allow override of components
|
83
|
+
# config_override.each do |key, value|
|
84
|
+
# @config[key] = value
|
85
|
+
# end unless config_override.nil?
|
86
|
+
|
87
|
+
Dir[candidate_mappings_path].each do |mapping_file|
|
88
|
+
mappings = YAML.load(File.read(mapping_file))
|
89
|
+
@component_files << mapping_file
|
90
|
+
mappings.each do |name, map|
|
91
|
+
@mappings[name] = map
|
92
|
+
end unless mappings.nil?
|
93
|
+
end
|
94
|
+
|
95
|
+
if File.exist? candidate_dynamic_mappings_path
|
96
|
+
require candidate_dynamic_mappings_path
|
97
|
+
@component_files << candidate_dynamic_mappings_path
|
98
|
+
end
|
99
|
+
|
100
|
+
# 1st pass - parse the file
|
101
|
+
@component_files << @highlander_dsl_path
|
102
|
+
@highlander_dsl = eval(File.read(@highlander_dsl_path), binding)
|
103
|
+
|
104
|
+
# set version if not defined
|
105
|
+
@highlander_dsl.ComponentVersion(@version) unless @version.nil?
|
106
|
+
|
107
|
+
|
108
|
+
# Handle name and description defaults if they are not specified
|
109
|
+
# in template itself
|
110
|
+
if @highlander_dsl.name.nil?
|
111
|
+
@highlander_dsl.name = @name
|
112
|
+
end
|
113
|
+
|
114
|
+
if @highlander_dsl.description.nil?
|
115
|
+
@highlander_dsl.Description("#{@highlander_dsl.name} - #{@highlander_dsl.version}")
|
116
|
+
end
|
117
|
+
|
118
|
+
# set (override) distribution options
|
119
|
+
@highlander_dsl.DistributionBucket(@distribution_bucket) unless @distribution_bucket.nil?
|
120
|
+
@highlander_dsl.DistributionPrefix(@distribution_prefix) unless @distribution_prefix.nil?
|
121
|
+
|
122
|
+
if File.exist? @cfndsl_path
|
123
|
+
@component_files << @cfndsl_path
|
124
|
+
@cfndsl_content = File.read(@cfndsl_path)
|
125
|
+
@cfndsl_content.strip!
|
126
|
+
# if there is CloudFormation do [content] end extract only contents
|
127
|
+
### Regex \s is whitespace
|
128
|
+
match_data = /^CloudFormation do\s(.*)end\s?$/m.match(@cfndsl_content)
|
129
|
+
if not match_data.nil?
|
130
|
+
@cfndsl_content = match_data[1]
|
131
|
+
end
|
132
|
+
|
133
|
+
else
|
134
|
+
@cfndsl_content = ''
|
135
|
+
end
|
136
|
+
|
137
|
+
loadDepandantExt()
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class ComponentFactory
|
142
|
+
|
143
|
+
attr_accessor :component_sources
|
144
|
+
|
145
|
+
|
146
|
+
def initialize(component_sources = [])
|
147
|
+
## First look in local $PWD/components folder
|
148
|
+
## Then search for cached $HOME/.highlander/components
|
149
|
+
## Then search in sources given by dsl
|
150
|
+
default_locations = [
|
151
|
+
LOCAL_HIGHLANDER_CACHE_LOCATION,
|
152
|
+
File.expand_path('components'),
|
153
|
+
File.expand_path('.')
|
154
|
+
]
|
155
|
+
default_locations.each do |predefined_path|
|
156
|
+
component_sources.unshift(predefined_path)
|
157
|
+
end
|
158
|
+
|
159
|
+
@component_sources = component_sources
|
160
|
+
end
|
161
|
+
|
162
|
+
def findComponentDefault(component_name, component_version)
|
163
|
+
default_lookup_url = 'https://github.com/theonestack'
|
164
|
+
default_lookup_url = ENV['HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'] if ENV.key? 'HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'
|
165
|
+
|
166
|
+
git_url = "#{default_lookup_url}/hl-component-#{component_name}"
|
167
|
+
|
168
|
+
if component_version.nil? or component_version.empty? or component_version == 'latest'
|
169
|
+
branch = 'master'
|
170
|
+
else
|
171
|
+
branch = component_version
|
172
|
+
end
|
173
|
+
local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
|
174
|
+
return findComponentGit(local_path, component_name, component_version, git_url, branch)
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
def findComponentGit(local_path, component_name, component_version, git_url, branch)
|
179
|
+
begin
|
180
|
+
local_path = "#{local_path}/" unless local_path.end_with? '/'
|
181
|
+
# if this is snapshot, clean local cache
|
182
|
+
if branch.end_with? '.snapshot'
|
183
|
+
branch = branch.gsub('.snapshot', '')
|
184
|
+
FileUtils.rmtree local_path if File.exist? local_path and File.directory? local_path
|
185
|
+
end
|
186
|
+
|
187
|
+
# if local cache exists, return from cache
|
188
|
+
if not Dir.glob("#{local_path}*.highlander.rb").empty?
|
189
|
+
# if cache exists, just return from cache
|
190
|
+
component_name = Dir.glob("#{local_path}*.highlander.rb")[0].gsub(local_path, '').gsub('.highlander.rb','')
|
191
|
+
return component_name, local_path
|
192
|
+
end
|
193
|
+
|
194
|
+
# shallow clone
|
195
|
+
puts "Trying to load #{component_name}/#{component_version} from #{git_url}##{branch} ... "
|
196
|
+
clone_opts = { depth: 1 }
|
197
|
+
clone_opts[:branch] = branch if not (branch.nil? or branch.empty?)
|
198
|
+
Git.clone git_url, local_path, clone_opts
|
199
|
+
puts "\t .. cached in #{local_path}\n"
|
200
|
+
# return from cache once it's cloned
|
201
|
+
return findComponentGit(local_path, component_name, component_version, git_url, branch)
|
202
|
+
rescue Exception => e
|
203
|
+
STDERR.puts "Failed to resolve component #{component_name}@#{component_version} from #{git_url}"
|
204
|
+
STDERR.puts e
|
205
|
+
return nil
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def findComponentS3(s3_location, component_name, component_version)
|
210
|
+
parts = s3_location.split('/')
|
211
|
+
bucket = parts[2]
|
212
|
+
prefix = parts[3]
|
213
|
+
s3_key = "#{prefix}/#{component_name}/#{component_version}/#{component_name}.highlander.rb"
|
214
|
+
s3_prefix = "#{prefix}/#{component_name}/#{component_version}/"
|
215
|
+
local_destination = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
|
216
|
+
begin
|
217
|
+
s3 = Aws::S3::Client.new({ region: s3_bucket_region(bucket) })
|
218
|
+
FileUtils.mkdir_p local_destination unless Dir.exist? local_destination
|
219
|
+
|
220
|
+
hl_content = s3.get_object({ bucket: bucket,
|
221
|
+
key: s3_key,
|
222
|
+
response_target: "#{local_destination}/#{component_name}.highlander.rb"
|
223
|
+
})
|
224
|
+
# if code execution got so far we consider file exists and download it locally
|
225
|
+
component_files = s3.list_objects_v2({ bucket: bucket, prefix: s3_prefix })
|
226
|
+
component_files.contents.each {|s3_object|
|
227
|
+
file_name = s3_object.key.gsub(s3_prefix, '')
|
228
|
+
destination_file = "#{local_destination}/#{file_name}"
|
229
|
+
destination_dir = File.dirname(destination_file)
|
230
|
+
print "Caching #{file_name} of #{component_name}@#{component_version} in #{destination_dir} ... "
|
231
|
+
|
232
|
+
FileUtils.mkpath(destination_dir) unless File.exists?(destination_dir)
|
233
|
+
s3.get_object({ bucket: bucket, key: s3_object.key, response_target: destination_file })
|
234
|
+
print " [OK] \n"
|
235
|
+
}
|
236
|
+
return local_destination
|
237
|
+
rescue => e
|
238
|
+
# this handles both nonexisting key and bucket
|
239
|
+
puts("#{component_name} not found in s3://#{bucket}/#{prefix}")
|
240
|
+
STDERR.puts(e.to_s) unless e.message.include? 'does not exist'
|
241
|
+
return nil
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def findComponentGitTemplate(component_name, component_version)
|
246
|
+
if component_name.include? '#'
|
247
|
+
parts = component_name.split('#')
|
248
|
+
component_name = parts[0]
|
249
|
+
component_version = parts[1]
|
250
|
+
end
|
251
|
+
|
252
|
+
# avoid any nres
|
253
|
+
component_version = '' if component_version.nil?
|
254
|
+
|
255
|
+
# if empty or latest branch is empty
|
256
|
+
if component_version.empty? or component_version == 'latest' or component_version == 'latest.snapshot'
|
257
|
+
branch = ''
|
258
|
+
else
|
259
|
+
# otherwise component version is actual branch
|
260
|
+
branch = component_version
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
git_url = nil
|
265
|
+
if component_name.start_with? 'git:'
|
266
|
+
git_url = component_name.gsub('git:', '')
|
267
|
+
elsif component_name.start_with? 'github:'
|
268
|
+
git_url = "https://github.com/#{component_name.gsub('github:', '')}"
|
269
|
+
elsif component_name.start_with? 'github.com:'
|
270
|
+
git_url = "https://github.com/#{component_name.gsub('github.com:', '')}"
|
271
|
+
end
|
272
|
+
|
273
|
+
local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
|
274
|
+
|
275
|
+
if not git_url.nil?
|
276
|
+
component_name, location = findComponentGit(local_path, component_name, component_version, git_url, branch)
|
277
|
+
if location.nil?
|
278
|
+
raise "Could not resolve component #{component_name}@#{component_version}"
|
279
|
+
else
|
280
|
+
return component_name, location
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
return nil
|
285
|
+
end
|
286
|
+
|
287
|
+
# Find component and given list of sources
|
288
|
+
# @return [Highlander::Factory::Component]
|
289
|
+
def findComponent(component_name, component_version = nil)
|
290
|
+
|
291
|
+
component_version_s = component_version.nil? ? 'latest' : component_version
|
292
|
+
component_version = nil if component_version == 'latest'
|
293
|
+
|
294
|
+
if component_name.include? '@' and (not component_name.start_with? 'git')
|
295
|
+
parts = component_name.split('@')
|
296
|
+
component_name = parts[0]
|
297
|
+
component_version = parts[1]
|
298
|
+
end
|
299
|
+
|
300
|
+
# if component specified as git location
|
301
|
+
new_name, candidate_git = findComponentGitTemplate(component_name, component_version_s)
|
302
|
+
return buildComponent(new_name, candidate_git) unless candidate_git.nil?
|
303
|
+
|
304
|
+
# if not git but has .snapshot lookup in default
|
305
|
+
if (not component_version.nil?) and component_version.end_with? '.snapshot'
|
306
|
+
new_name, default_candidate = findComponentDefault(component_name, component_version_s)
|
307
|
+
return buildComponent(new_name, default_candidate) unless default_candidate.nil?
|
308
|
+
end
|
309
|
+
|
310
|
+
# try in all of the component source
|
311
|
+
@component_sources.each do |source|
|
312
|
+
component_full_name = "#{component_name}@#{component_version.nil? ? 'latest' : component_version}"
|
313
|
+
# TODO handle http(s) sources and their download to local
|
314
|
+
if source.start_with?('http')
|
315
|
+
raise StandardError, 'http(s) sources not supported yet'
|
316
|
+
elsif source.start_with?('s3://')
|
317
|
+
# s3 candidate
|
318
|
+
|
319
|
+
s3_candidate = findComponentS3(source, component_name, component_version_s)
|
320
|
+
if not s3_candidate.nil?
|
321
|
+
# at this point all component files are download to local file system and consumed from there
|
322
|
+
return buildComponent(component_name, s3_candidate)
|
323
|
+
end
|
324
|
+
|
325
|
+
else
|
326
|
+
# file system candidate
|
327
|
+
candidate = "#{source}/#{component_name}"
|
328
|
+
candidate = "#{candidate}/#{component_version}" unless component_version.nil?
|
329
|
+
candidate_hl_path = "#{candidate}/#{component_name}.highlander.rb"
|
330
|
+
candidate2_hl_path = "#{source}/#{component_name}.highlander.rb"
|
331
|
+
puts "Trying to load #{component_full_name} from #{candidate} ... "
|
332
|
+
if File.exist?(candidate_hl_path)
|
333
|
+
return buildComponent(component_name, candidate)
|
334
|
+
end
|
335
|
+
puts "Trying to load #{component_full_name} from #{source} ... "
|
336
|
+
if File.exist?(candidate2_hl_path)
|
337
|
+
return buildComponent(component_name, source)
|
338
|
+
end unless component_version_s != 'latest'
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
# try default component source on github
|
343
|
+
component_name, default_candidate = findComponentDefault(component_name, component_version_s)
|
344
|
+
return buildComponent(component_name, default_candidate) unless default_candidate.nil?
|
345
|
+
|
346
|
+
raise StandardError, "highlander template #{component_name}@#{component_version_s} not located" +
|
347
|
+
" in sources #{@component_sources}"
|
348
|
+
end
|
349
|
+
|
350
|
+
def buildComponent(component_name, component_dir)
|
351
|
+
component = Component.new(component_name, component_dir)
|
352
|
+
component.load_config
|
353
|
+
return component
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|