cfhighlander 0.2.1.alpha.29 → 0.2.1.alpha.32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/cfhighlander.rb +2 -2
- data/lib/highlander.dsl.component.rb +1 -1
- data/lib/highlander.dsl.rb +5 -5
- data/lib/highlander.factory.rb +10 -331
- data/lib/highlander.factory.templatefinder.rb +231 -0
- data/lib/highlander.model.component.rb +147 -0
- data/lib/highlander.model.templatemeta.rb +25 -0
- data/lib/highlander.publisher.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8270727d240fc67a59aee1024d65559ba511a6e4fc8cddcbb92cfbca8f596d5d
|
4
|
+
data.tar.gz: 9ef339afe459632b9f894f064f1f008e202d0572329009e762e385939e0e2a76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e083c0ba93e947c211de515119588558e70c6308b495fed0f3513a5fada0b359a0fac540ea02a180a0fca3526be5997fc05983bdc2c0af3720e0c15e4ed22af
|
7
|
+
data.tar.gz: 5971ab0b2b99eb615f923a39bbee02656cbed12b6cbc3f22df91dc83ac2d8fdfef56c559bef8ff3935cd4b1331395cf3b9c0ceb4f212f0db38f8bc513a11052f
|
data/bin/cfhighlander.rb
CHANGED
@@ -103,7 +103,7 @@ class HighlanderCli < Thor
|
|
103
103
|
|
104
104
|
def cfpublish(component_name)
|
105
105
|
compiler = cfcompile(component_name)
|
106
|
-
publisher = Highlander::Publisher::
|
106
|
+
publisher = Highlander::Publisher::ComponentPublisher.new(compiler.component, false)
|
107
107
|
publisher.publishFiles(compiler.cfn_template_paths + compiler.lambda_src_paths)
|
108
108
|
end
|
109
109
|
|
@@ -130,7 +130,7 @@ class HighlanderCli < Thor
|
|
130
130
|
component.distribution_prefix = distribution_prefix unless distribution_prefix.nil?
|
131
131
|
component.load
|
132
132
|
|
133
|
-
publisher = Highlander::Publisher::
|
133
|
+
publisher = Highlander::Publisher::ComponentPublisher.new(component, true)
|
134
134
|
publisher.publishComponent
|
135
135
|
end
|
136
136
|
|
data/lib/highlander.dsl.rb
CHANGED
@@ -16,7 +16,7 @@ module Highlander
|
|
16
16
|
|
17
17
|
module Dsl
|
18
18
|
|
19
|
-
class
|
19
|
+
class HighlanderTemplate < DslBase
|
20
20
|
|
21
21
|
attr_accessor :mappings,
|
22
22
|
:parameters,
|
@@ -86,7 +86,7 @@ module Highlander
|
|
86
86
|
puts "Initialize #{name} with template #{template}"
|
87
87
|
|
88
88
|
# load component
|
89
|
-
component = Highlander::Dsl::
|
89
|
+
component = Highlander::Dsl::Subcomponent.new(self,
|
90
90
|
name,
|
91
91
|
template,
|
92
92
|
param_values,
|
@@ -220,7 +220,7 @@ module Highlander
|
|
220
220
|
}
|
221
221
|
|
222
222
|
@dependson_components_templates.each do |template|
|
223
|
-
component = Highlander::Dsl::
|
223
|
+
component = Highlander::Dsl::Subcomponent.new(self,
|
224
224
|
template,
|
225
225
|
template,
|
226
226
|
{},
|
@@ -400,7 +400,7 @@ module Highlander
|
|
400
400
|
end
|
401
401
|
|
402
402
|
def HighlanderComponent(&block)
|
403
|
-
instance = Highlander::Dsl::
|
403
|
+
instance = Highlander::Dsl::HighlanderTemplate.new
|
404
404
|
|
405
405
|
puts "Processing higlander component #{@name}\n\tLocation:#{@highlander_dsl_path}" +
|
406
406
|
"\n\tConfig:#{@config}"
|
@@ -424,7 +424,7 @@ def HighlanderComponent(&block)
|
|
424
424
|
instance.DistributionPrefix(@distribution_prefix)
|
425
425
|
end
|
426
426
|
|
427
|
-
instance.name = @template
|
427
|
+
instance.name = @template.template_name
|
428
428
|
instance.instance_eval(&block)
|
429
429
|
|
430
430
|
|
data/lib/highlander.factory.rb
CHANGED
@@ -1,359 +1,38 @@
|
|
1
1
|
require_relative './highlander.dsl'
|
2
|
+
require_relative './highlander.factory.templatefinder'
|
3
|
+
require_relative './highlander.model.component'
|
2
4
|
require 'fileutils'
|
3
5
|
require 'git'
|
4
6
|
|
5
|
-
LOCAL_HIGHLANDER_CACHE_LOCATION = "#{ENV['HOME']}/.cfhighlander/components"
|
6
7
|
|
7
8
|
module Highlander
|
8
9
|
|
9
10
|
module Factory
|
10
11
|
|
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
|
-
:template,
|
22
|
-
:version,
|
23
|
-
:distribution_bucket,
|
24
|
-
:distribution_prefix,
|
25
|
-
:component_files,
|
26
|
-
:cfndsl_ext_files,
|
27
|
-
:lambda_src_files
|
28
|
-
|
29
|
-
def initialize(component_template_name,
|
30
|
-
component_template_version,
|
31
|
-
component_name, component_dir)
|
32
|
-
@template = component_template_name
|
33
|
-
@name = component_name
|
34
|
-
@component_dir = component_dir
|
35
|
-
@mappings = {}
|
36
|
-
@version = component_template_version
|
37
|
-
@distribution_bucket = nil
|
38
|
-
@distribution_prefix = nil
|
39
|
-
@component_files = []
|
40
|
-
@cfndsl_ext_files = []
|
41
|
-
@lambda_src_files = []
|
42
|
-
end
|
43
|
-
|
44
|
-
def load_config()
|
45
|
-
@config = {} if @config.nil?
|
46
|
-
Dir["#{@component_dir}/*.config.yaml"].each do |config_file|
|
47
|
-
puts "Loading config for #{@name}:\n\tread #{config_file} "
|
48
|
-
partial_config = YAML.load(File.read(config_file))
|
49
|
-
unless partial_config.nil?
|
50
|
-
@config.extend(partial_config)
|
51
|
-
@component_files << config_file
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
def loadDepandantExt()
|
58
|
-
@highlander_dsl.dependson_components.each do |requirement|
|
59
|
-
requirement.component_loaded.cfndsl_ext_files.each do |file|
|
60
|
-
cfndsl_ext_files << file
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# @param [Hash] config_override
|
66
|
-
def load(config_override = nil)
|
67
|
-
if @component_dir.start_with? 'http'
|
68
|
-
raise StandardError, 'http(s) sources not supported yet'
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
@highlander_dsl_path = "#{@component_dir}/#{@template}.highlander.rb"
|
73
|
-
@cfndsl_path = "#{@component_dir}/#{@template}.cfndsl.rb"
|
74
|
-
candidate_mappings_path = "#{@component_dir}/*.mappings.yaml"
|
75
|
-
candidate_dynamic_mappings_path = "#{@component_dir}/#{@template}.mappings.rb"
|
76
|
-
|
77
|
-
@cfndsl_ext_files += Dir["#{@component_dir}/ext/cfndsl/*.rb"]
|
78
|
-
@lambda_src_files += Dir["#{@component_dir}/lambdas/**/*"].find_all {|p| not File.directory? p}
|
79
|
-
@component_files += @cfndsl_ext_files
|
80
|
-
@component_files += @lambda_src_files
|
81
|
-
|
82
|
-
@config = {} if @config.nil?
|
83
|
-
|
84
|
-
@config.extend config_override unless config_override.nil?
|
85
|
-
@config['component_version'] = @version unless @version.nil?
|
86
|
-
@config['component_name'] = @name
|
87
|
-
# allow override of components
|
88
|
-
# config_override.each do |key, value|
|
89
|
-
# @config[key] = value
|
90
|
-
# end unless config_override.nil?
|
91
|
-
|
92
|
-
Dir[candidate_mappings_path].each do |mapping_file|
|
93
|
-
mappings = YAML.load(File.read(mapping_file))
|
94
|
-
@component_files << mapping_file
|
95
|
-
mappings.each do |name, map|
|
96
|
-
@mappings[name] = map
|
97
|
-
end unless mappings.nil?
|
98
|
-
end
|
99
|
-
|
100
|
-
if File.exist? candidate_dynamic_mappings_path
|
101
|
-
require candidate_dynamic_mappings_path
|
102
|
-
@component_files << candidate_dynamic_mappings_path
|
103
|
-
end
|
104
|
-
|
105
|
-
# 1st pass - parse the file
|
106
|
-
@component_files << @highlander_dsl_path
|
107
|
-
@highlander_dsl = eval(File.read(@highlander_dsl_path), binding)
|
108
|
-
# set version if not defined
|
109
|
-
@highlander_dsl.ComponentVersion(@version) unless @version.nil?
|
110
|
-
|
111
|
-
|
112
|
-
if @highlander_dsl.description.nil?
|
113
|
-
@highlander_dsl.Description("#{@highlander_dsl.name} - #{@highlander_dsl.version}")
|
114
|
-
end
|
115
|
-
|
116
|
-
# set (override) distribution options
|
117
|
-
@highlander_dsl.DistributionBucket(@distribution_bucket) unless @distribution_bucket.nil?
|
118
|
-
@highlander_dsl.DistributionPrefix(@distribution_prefix) unless @distribution_prefix.nil?
|
119
|
-
|
120
|
-
if File.exist? @cfndsl_path
|
121
|
-
@component_files << @cfndsl_path
|
122
|
-
@cfndsl_content = File.read(@cfndsl_path)
|
123
|
-
@cfndsl_content.strip!
|
124
|
-
# if there is CloudFormation do [content] end extract only contents
|
125
|
-
### Regex \s is whitespace
|
126
|
-
match_data = /^CloudFormation do\s(.*)end\s?$/m.match(@cfndsl_content)
|
127
|
-
if not match_data.nil?
|
128
|
-
@cfndsl_content = match_data[1]
|
129
|
-
end
|
130
|
-
|
131
|
-
else
|
132
|
-
@cfndsl_content = ''
|
133
|
-
end
|
134
|
-
|
135
|
-
loadDepandantExt()
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
12
|
class ComponentFactory
|
140
13
|
|
141
14
|
attr_accessor :component_sources
|
142
15
|
|
143
|
-
|
144
16
|
def initialize(component_sources = [])
|
145
|
-
|
146
|
-
## Then search for cached $HOME/.highlander/components
|
147
|
-
## Then search in sources given by dsl
|
148
|
-
default_locations = [
|
149
|
-
LOCAL_HIGHLANDER_CACHE_LOCATION,
|
150
|
-
File.expand_path('components'),
|
151
|
-
File.expand_path('.')
|
152
|
-
]
|
153
|
-
default_locations.each do |predefined_path|
|
154
|
-
component_sources.unshift(predefined_path)
|
155
|
-
end
|
156
|
-
|
157
|
-
@component_sources = component_sources
|
158
|
-
end
|
159
|
-
|
160
|
-
def findTemplateDefault(template_name, component_version)
|
161
|
-
default_lookup_url = 'https://github.com/theonestack'
|
162
|
-
default_lookup_url = ENV['HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'] if ENV.key? 'HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'
|
163
|
-
|
164
|
-
git_url = "#{default_lookup_url}/hl-component-#{template_name}"
|
165
|
-
|
166
|
-
if component_version.nil? or component_version.empty? or component_version == 'latest'
|
167
|
-
branch = 'master'
|
168
|
-
else
|
169
|
-
branch = component_version
|
170
|
-
end
|
171
|
-
local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{template_name}/#{component_version}"
|
172
|
-
return findTemplateGit(local_path, template_name, component_version, git_url, branch)
|
173
|
-
|
174
|
-
end
|
175
|
-
|
176
|
-
def findTemplateGit(cache_path, component_name, component_version, git_url, branch)
|
177
|
-
begin
|
178
|
-
cache_path = "#{cache_path}/" unless cache_path.end_with? '/'
|
179
|
-
# if this is snapshot, clean local cache
|
180
|
-
if branch.end_with? '.snapshot'
|
181
|
-
branch = branch.gsub('.snapshot', '')
|
182
|
-
FileUtils.rmtree cache_path if File.exist? cache_path and File.directory? cache_path
|
183
|
-
end
|
184
|
-
|
185
|
-
# if local cache exists, return from cache
|
186
|
-
if not Dir.glob("#{cache_path}*.highlander.rb").empty?
|
187
|
-
# if cache exists, just return from cache
|
188
|
-
component_name = Dir.glob("#{cache_path}*.highlander.rb")[0].gsub(cache_path, '').gsub('.highlander.rb', '')
|
189
|
-
return component_name, cache_path
|
190
|
-
end
|
191
|
-
|
192
|
-
# shallow clone
|
193
|
-
puts "Trying to load #{component_name}/#{component_version} from #{git_url}##{branch} ... "
|
194
|
-
clone_opts = { depth: 1 }
|
195
|
-
clone_opts[:branch] = branch if not (branch.nil? or branch.empty?)
|
196
|
-
Git.clone git_url, cache_path, clone_opts
|
197
|
-
puts "\t .. cached in #{cache_path}\n"
|
198
|
-
# return from cache once it's cloned
|
199
|
-
return findTemplateGit(cache_path, component_name, component_version, git_url, branch)
|
200
|
-
rescue Exception => e
|
201
|
-
STDERR.puts "Failed to resolve component #{component_name}@#{component_version} from #{git_url}"
|
202
|
-
STDERR.puts e
|
203
|
-
return nil
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def findTemplateS3(s3_location, component_name, component_version)
|
208
|
-
parts = s3_location.split('/')
|
209
|
-
bucket = parts[2]
|
210
|
-
prefix = parts[3]
|
211
|
-
s3_key = "#{prefix}/#{component_name}/#{component_version}/#{component_name}.highlander.rb"
|
212
|
-
s3_prefix = "#{prefix}/#{component_name}/#{component_version}/"
|
213
|
-
local_destination = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
|
214
|
-
begin
|
215
|
-
s3 = Aws::S3::Client.new({ region: s3_bucket_region(bucket) })
|
216
|
-
FileUtils.mkdir_p local_destination unless Dir.exist? local_destination
|
217
|
-
|
218
|
-
hl_content = s3.get_object({ bucket: bucket,
|
219
|
-
key: s3_key,
|
220
|
-
response_target: "#{local_destination}/#{component_name}.highlander.rb"
|
221
|
-
})
|
222
|
-
# if code execution got so far we consider file exists and download it locally
|
223
|
-
component_files = s3.list_objects_v2({ bucket: bucket, prefix: s3_prefix })
|
224
|
-
component_files.contents.each {|s3_object|
|
225
|
-
file_name = s3_object.key.gsub(s3_prefix, '')
|
226
|
-
destination_file = "#{local_destination}/#{file_name}"
|
227
|
-
destination_dir = File.dirname(destination_file)
|
228
|
-
print "Caching #{file_name} of #{component_name}@#{component_version} in #{destination_dir} ... "
|
229
|
-
|
230
|
-
FileUtils.mkpath(destination_dir) unless File.exists?(destination_dir)
|
231
|
-
s3.get_object({ bucket: bucket, key: s3_object.key, response_target: destination_file })
|
232
|
-
print " [OK] \n"
|
233
|
-
}
|
234
|
-
return local_destination
|
235
|
-
rescue => e
|
236
|
-
# this handles both nonexisting key and bucket
|
237
|
-
puts("#{component_name} not found in s3://#{bucket}/#{prefix}")
|
238
|
-
STDERR.puts(e.to_s) unless e.message.include? 'does not exist'
|
239
|
-
return nil
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
# will try and locate template based on git template location
|
244
|
-
# if template location is not git repo, returns nil
|
245
|
-
def tryFindTemplateGit(template_location, template_version)
|
246
|
-
if template_location.include? '#'
|
247
|
-
parts = template_location.split('#')
|
248
|
-
template_location = parts[0]
|
249
|
-
template_version = parts[1]
|
250
|
-
end
|
251
|
-
|
252
|
-
# avoid any nres
|
253
|
-
template_version = '' if template_version.nil?
|
254
|
-
|
255
|
-
# if empty or latest branch is empty
|
256
|
-
if template_version.empty? or template_version == 'latest' or template_version == 'latest.snapshot'
|
257
|
-
branch = ''
|
258
|
-
else
|
259
|
-
# otherwise component version is actual branch
|
260
|
-
branch = template_version
|
261
|
-
end
|
262
|
-
|
263
|
-
|
264
|
-
git_url = nil
|
265
|
-
if template_location.start_with? 'git:'
|
266
|
-
git_url = template_location.gsub('git:', '')
|
267
|
-
elsif template_location.start_with? 'github:'
|
268
|
-
git_url = "https://github.com/#{template_location.gsub('github:', '')}"
|
269
|
-
elsif template_location.start_with? 'github.com:'
|
270
|
-
git_url = "https://github.com/#{template_location.gsub('github.com:', '')}"
|
271
|
-
end
|
272
|
-
|
273
|
-
local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{template_location}/#{template_version}"
|
274
|
-
|
275
|
-
if not git_url.nil?
|
276
|
-
template_name, location = findTemplateGit(local_path, template_location, template_version, git_url, branch)
|
277
|
-
if location.nil?
|
278
|
-
raise "Could not resolve component #{template_location}@#{template_version}"
|
279
|
-
else
|
280
|
-
return template_name, template_version, location
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
return nil
|
17
|
+
@template_finder = Highlander::Factory::TemplateFinder.new(component_sources)
|
285
18
|
end
|
286
19
|
|
287
20
|
# Find component and given list of sources
|
288
21
|
# @return [Highlander::Factory::Component]
|
289
22
|
def loadComponentFromTemplate(template_name, template_version = nil, component_name = nil)
|
290
23
|
|
291
|
-
|
292
|
-
template_version = nil if template_version == 'latest'
|
293
|
-
component_name = template_name if component_name.nil?
|
294
|
-
|
295
|
-
if template_name.include? '@' and (not template_name.start_with? 'git')
|
296
|
-
parts = template_name.split('@')
|
297
|
-
template_name = parts[0]
|
298
|
-
template_version = parts[1]
|
299
|
-
component_version_s = template_version
|
300
|
-
end
|
24
|
+
template_meta = @template_finder.findTemplate(template_name, template_version)
|
301
25
|
|
302
|
-
|
303
|
-
|
304
|
-
return buildComponentFromLocation(new_template_name, new_version, component_name, candidate_git) unless candidate_git.nil?
|
305
|
-
|
306
|
-
# if not git but has .snapshot lookup in default
|
307
|
-
if (not template_version.nil?) and template_version.end_with? '.snapshot'
|
308
|
-
new_template_name, default_candidate = findTemplateDefault(template_name, component_version_s)
|
309
|
-
return buildComponentFromLocation(new_template_name, template_version, component_name, default_candidate) unless default_candidate.nil?
|
310
|
-
end
|
311
|
-
|
312
|
-
# try in all of the component source
|
313
|
-
@component_sources.each do |source|
|
314
|
-
component_full_name = "#{template_name}@#{template_version.nil? ? 'latest' : template_version}"
|
315
|
-
# TODO handle http(s) sources and their download to local
|
316
|
-
if source.start_with?('http')
|
317
|
-
raise StandardError, 'http(s) sources not supported yet'
|
318
|
-
elsif source.start_with?('s3://')
|
319
|
-
# s3 candidate
|
320
|
-
|
321
|
-
s3_candidate = findTemplateS3(source, template_name, component_version_s)
|
322
|
-
if not s3_candidate.nil?
|
323
|
-
# at this point all component files are download to local file system and consumed from there
|
324
|
-
return buildComponentFromLocation(template_name, template_version, component_name, s3_candidate)
|
325
|
-
end
|
326
|
-
|
327
|
-
else
|
328
|
-
# file system candidate
|
329
|
-
candidate = "#{source}/#{template_name}"
|
330
|
-
candidate = "#{candidate}/#{template_version}" unless template_version.nil?
|
331
|
-
candidate_hl_path = "#{candidate}/#{template_name}.highlander.rb"
|
332
|
-
candidate2_hl_path = "#{source}/#{template_name}.highlander.rb"
|
333
|
-
puts "Trying to load #{component_full_name} from #{candidate} ... "
|
334
|
-
if File.exist?(candidate_hl_path)
|
335
|
-
return buildComponentFromLocation(template_name, template_version, component_name, candidate)
|
336
|
-
end
|
337
|
-
puts "Trying to load #{component_full_name} from #{source} ... "
|
338
|
-
if File.exist?(candidate2_hl_path)
|
339
|
-
return buildComponentFromLocation(template_name, template_version, component_name, source)
|
340
|
-
end unless component_version_s != 'latest'
|
341
|
-
end
|
342
|
-
end
|
26
|
+
raise StandardError, "highlander template #{template_name}@#{component_version_s} not located" +
|
27
|
+
" in sources #{@component_sources}" if template_meta.nil?
|
343
28
|
|
344
|
-
|
345
|
-
template_name, default_candidate = findTemplateDefault(template_name, component_version_s)
|
346
|
-
return buildComponentFromLocation(template_name, template_version, component_name, default_candidate) unless default_candidate.nil?
|
29
|
+
return buildComponentFromLocation(template_meta, component_name)
|
347
30
|
|
348
|
-
raise StandardError, "highlander template #{template_name}@#{component_version_s} not located" +
|
349
|
-
" in sources #{@component_sources}"
|
350
31
|
end
|
351
32
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
template_location)
|
356
|
-
component = Component.new(template_name, template_version, component_name, template_location)
|
33
|
+
|
34
|
+
def buildComponentFromLocation(template_meta, component_name)
|
35
|
+
component = Model::Component.new(template_meta, component_name)
|
357
36
|
component.load_config
|
358
37
|
return component
|
359
38
|
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
LOCAL_HIGHLANDER_CACHE_LOCATION = "#{ENV['HOME']}/.cfhighlander/components"
|
2
|
+
|
3
|
+
require_relative './highlander.model.templatemeta'
|
4
|
+
|
5
|
+
module Highlander
|
6
|
+
|
7
|
+
module Factory
|
8
|
+
|
9
|
+
class TemplateFinder
|
10
|
+
|
11
|
+
def initialize(component_sources = [])
|
12
|
+
## First look in local $PWD/components folder
|
13
|
+
## Then search for cached $HOME/.highlander/components
|
14
|
+
## Then search in sources given by dsl
|
15
|
+
default_locations = [
|
16
|
+
LOCAL_HIGHLANDER_CACHE_LOCATION,
|
17
|
+
File.expand_path('components'),
|
18
|
+
File.expand_path('.')
|
19
|
+
]
|
20
|
+
default_locations.each do |predefined_path|
|
21
|
+
component_sources.unshift(predefined_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
@component_sources = component_sources
|
25
|
+
end
|
26
|
+
|
27
|
+
def findTemplateDefault(template_name, component_version)
|
28
|
+
default_lookup_url = 'https://github.com/theonestack'
|
29
|
+
default_lookup_url = ENV['HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'] if ENV.key? 'HIGHLANDER_DEFAULT_COMPONENT_GIT_LOOKUP'
|
30
|
+
|
31
|
+
git_url = "#{default_lookup_url}/hl-component-#{template_name}"
|
32
|
+
|
33
|
+
if component_version.nil? or component_version.empty? or component_version == 'latest'
|
34
|
+
branch = 'master'
|
35
|
+
else
|
36
|
+
branch = component_version
|
37
|
+
end
|
38
|
+
local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{template_name}/#{component_version}"
|
39
|
+
return findTemplateGit(local_path, template_name, component_version, git_url, branch)
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def findTemplateGit(cache_path, component_name, component_version, git_url, branch)
|
44
|
+
begin
|
45
|
+
cache_path = "#{cache_path}/" unless cache_path.end_with? '/'
|
46
|
+
# if this is snapshot, clean local cache
|
47
|
+
if branch.end_with? '.snapshot'
|
48
|
+
branch = branch.gsub('.snapshot', '')
|
49
|
+
FileUtils.rmtree cache_path if File.exist? cache_path and File.directory? cache_path
|
50
|
+
end
|
51
|
+
|
52
|
+
# if local cache exists, return from cache
|
53
|
+
if not Dir.glob("#{cache_path}*.highlander.rb").empty?
|
54
|
+
# if cache exists, just return from cache
|
55
|
+
component_name = Dir.glob("#{cache_path}*.highlander.rb")[0].gsub(cache_path, '').gsub('.highlander.rb', '')
|
56
|
+
return component_name, cache_path
|
57
|
+
end
|
58
|
+
|
59
|
+
# shallow clone
|
60
|
+
puts "Trying to load #{component_name}/#{component_version} from #{git_url}##{branch} ... "
|
61
|
+
clone_opts = { depth: 1 }
|
62
|
+
clone_opts[:branch] = branch if not (branch.nil? or branch.empty?)
|
63
|
+
Git.clone git_url, cache_path, clone_opts
|
64
|
+
puts "\t .. cached in #{cache_path}\n"
|
65
|
+
# return from cache once it's cloned
|
66
|
+
return findTemplateGit(cache_path, component_name, component_version, git_url, branch)
|
67
|
+
rescue Exception => e
|
68
|
+
STDERR.puts "Failed to resolve component #{component_name}@#{component_version} from #{git_url}"
|
69
|
+
STDERR.puts e
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def findTemplateS3(s3_location, component_name, component_version)
|
75
|
+
parts = s3_location.split('/')
|
76
|
+
bucket = parts[2]
|
77
|
+
prefix = parts[3]
|
78
|
+
s3_key = "#{prefix}/#{component_name}/#{component_version}/#{component_name}.highlander.rb"
|
79
|
+
s3_prefix = "#{prefix}/#{component_name}/#{component_version}/"
|
80
|
+
local_destination = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{component_name}/#{component_version}"
|
81
|
+
begin
|
82
|
+
s3 = Aws::S3::Client.new({ region: s3_bucket_region(bucket) })
|
83
|
+
FileUtils.mkdir_p local_destination unless Dir.exist? local_destination
|
84
|
+
|
85
|
+
hl_content = s3.get_object({ bucket: bucket,
|
86
|
+
key: s3_key,
|
87
|
+
response_target: "#{local_destination}/#{component_name}.highlander.rb"
|
88
|
+
})
|
89
|
+
# if code execution got so far we consider file exists and download it locally
|
90
|
+
component_files = s3.list_objects_v2({ bucket: bucket, prefix: s3_prefix })
|
91
|
+
component_files.contents.each {|s3_object|
|
92
|
+
file_name = s3_object.key.gsub(s3_prefix, '')
|
93
|
+
destination_file = "#{local_destination}/#{file_name}"
|
94
|
+
destination_dir = File.dirname(destination_file)
|
95
|
+
print "Caching #{file_name} of #{component_name}@#{component_version} in #{destination_dir} ... "
|
96
|
+
|
97
|
+
FileUtils.mkpath(destination_dir) unless File.exists?(destination_dir)
|
98
|
+
s3.get_object({ bucket: bucket, key: s3_object.key, response_target: destination_file })
|
99
|
+
print " [OK] \n"
|
100
|
+
}
|
101
|
+
return local_destination
|
102
|
+
rescue => e
|
103
|
+
# this handles both nonexisting key and bucket
|
104
|
+
puts("#{component_name} not found in s3://#{bucket}/#{prefix}")
|
105
|
+
STDERR.puts(e.to_s) unless e.message.include? 'does not exist'
|
106
|
+
return nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# will try and locate template based on git template location
|
111
|
+
# if template location is not git repo, returns nil
|
112
|
+
def tryFindTemplateGit(template_location, template_version)
|
113
|
+
|
114
|
+
# avoid any nres
|
115
|
+
template_version = '' if template_version.nil?
|
116
|
+
|
117
|
+
# if empty or latest branch is empty
|
118
|
+
if template_version.empty? or template_version == 'latest' or template_version == 'latest.snapshot'
|
119
|
+
branch = ''
|
120
|
+
else
|
121
|
+
# otherwise component version is actual branch
|
122
|
+
branch = template_version
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
git_url = nil
|
127
|
+
if template_location.start_with? 'git:'
|
128
|
+
git_url = template_location.gsub('git:', '')
|
129
|
+
elsif template_location.start_with? 'github:'
|
130
|
+
git_url = "https://github.com/#{template_location.gsub('github:', '')}"
|
131
|
+
elsif template_location.start_with? 'github.com:'
|
132
|
+
git_url = "https://github.com/#{template_location.gsub('github.com:', '')}"
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
if not git_url.nil?
|
137
|
+
local_path = "#{LOCAL_HIGHLANDER_CACHE_LOCATION}/#{template_location.gsub(':', '_').gsub(/\/+/, '/')}/#{template_version}"
|
138
|
+
template_name, location = findTemplateGit(local_path, template_location, template_version, git_url, branch)
|
139
|
+
if location.nil?
|
140
|
+
raise "Could not resolve component #{template_location}@#{template_version}"
|
141
|
+
else
|
142
|
+
return template_name, template_version, location
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
return nil
|
147
|
+
end
|
148
|
+
|
149
|
+
def findTemplate(template_name, template_version)
|
150
|
+
template_version_s = template_version.nil? ? 'latest' : template_version
|
151
|
+
template_version = nil if template_version == 'latest'
|
152
|
+
is_git_template = template_name.start_with? 'git'
|
153
|
+
|
154
|
+
if template_name.include? '@' and (not template_name.start_with? 'git')
|
155
|
+
parts = template_name.split('@')
|
156
|
+
template_name = parts[0]
|
157
|
+
template_version = parts[1]
|
158
|
+
template_version_s = template_version
|
159
|
+
end
|
160
|
+
|
161
|
+
if template_name.include? '#' and (is_git_template)
|
162
|
+
parts = template_name.split('#')
|
163
|
+
template_name = parts[0]
|
164
|
+
template_version = parts[1]
|
165
|
+
template_version_s = template_version
|
166
|
+
end
|
167
|
+
|
168
|
+
# if component specified as git location
|
169
|
+
if is_git_template
|
170
|
+
new_template_name, new_version, candidate_git = tryFindTemplateGit(template_name, template_version_s)
|
171
|
+
return build_meta(new_template_name, new_version, candidate_git) unless candidate_git.nil?
|
172
|
+
end
|
173
|
+
|
174
|
+
# if not git but has .snapshot lookup in default, it is allowed to reference default
|
175
|
+
# snapshots
|
176
|
+
if (not template_version.nil?) and template_version.end_with? '.snapshot'
|
177
|
+
new_template_name, snapshot_candidate_location = findTemplateDefault(template_name, template_version_s)
|
178
|
+
return build_meta(new_template_name, template_version, snapshot_candidate_location) unless snapshot_candidate_location.nil?
|
179
|
+
end
|
180
|
+
|
181
|
+
# try in all of the component sources
|
182
|
+
@component_sources.each do |source|
|
183
|
+
template_full_name = "#{template_name}@#{template_version.nil? ? 'latest' : template_version}"
|
184
|
+
# TODO handle http(s) sources and their download to local
|
185
|
+
if source.start_with?('http')
|
186
|
+
raise StandardError, 'http(s) sources not supported yet'
|
187
|
+
elsif source.start_with?('s3://')
|
188
|
+
# s3 candidate
|
189
|
+
|
190
|
+
s3_candidate = findTemplateS3(source, template_name, template_version_s)
|
191
|
+
# at this point all component files are download to local file system and consumed from there
|
192
|
+
return build_meta(template_name, template_version_s, s3_candidate) unless s3_candidate.nil?
|
193
|
+
|
194
|
+
else
|
195
|
+
# file system candidate
|
196
|
+
candidate = "#{source}/#{template_name}"
|
197
|
+
candidate = "#{candidate}/#{template_version}" unless template_version.nil?
|
198
|
+
candidate_hl_path = "#{candidate}/#{template_name}.highlander.rb"
|
199
|
+
candidate2_hl_path = "#{source}/#{template_name}.highlander.rb"
|
200
|
+
puts "TRACE: Trying to load #{template_full_name} from #{candidate} ... "
|
201
|
+
if File.exist?(candidate_hl_path)
|
202
|
+
return build_meta(template_name, template_version_s, candidate)
|
203
|
+
end
|
204
|
+
puts "TRACE: Trying to load #{template_full_name} from #{source} ... "
|
205
|
+
# if component version is latest it is allowed to search in path
|
206
|
+
# with no version component in it
|
207
|
+
if File.exist?(candidate2_hl_path)
|
208
|
+
return build_meta(template_name, 'latest', source)
|
209
|
+
end unless template_version_s != 'latest'
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# try default component source on github
|
214
|
+
template_name, default_candidate = findTemplateDefault(template_name, template_version_s)
|
215
|
+
return build_meta(template_name, template_version_s, default_candidate) unless default_candidate.nil?
|
216
|
+
|
217
|
+
return nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def build_meta(template_name, template_version, template_location)
|
221
|
+
return Highlander::Model::TemplateMetadata.new(
|
222
|
+
template_name: template_name,
|
223
|
+
template_version: template_version,
|
224
|
+
template_location: template_location)
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Highlander
|
4
|
+
|
5
|
+
module Model
|
6
|
+
|
7
|
+
class Component
|
8
|
+
|
9
|
+
attr_accessor :component_dir,
|
10
|
+
:config,
|
11
|
+
:highlander_dsl_path,
|
12
|
+
:cfndsl_path,
|
13
|
+
:highlander_dsl,
|
14
|
+
:cfndsl_content,
|
15
|
+
:mappings,
|
16
|
+
:name,
|
17
|
+
:template,
|
18
|
+
:version,
|
19
|
+
:distribution_bucket,
|
20
|
+
:distribution_prefix,
|
21
|
+
:component_files,
|
22
|
+
:cfndsl_ext_files,
|
23
|
+
:lambda_src_files
|
24
|
+
|
25
|
+
def initialize(template_meta, component_name)
|
26
|
+
@template = template_meta
|
27
|
+
@name = component_name
|
28
|
+
@component_dir = template_meta.template_location
|
29
|
+
@mappings = {}
|
30
|
+
@version = template_meta.template_version
|
31
|
+
@distribution_bucket = nil
|
32
|
+
@distribution_prefix = nil
|
33
|
+
@component_files = []
|
34
|
+
@cfndsl_ext_files = []
|
35
|
+
@lambda_src_files = []
|
36
|
+
end
|
37
|
+
|
38
|
+
# load component configuration files
|
39
|
+
def load_config()
|
40
|
+
@config = {} if @config.nil?
|
41
|
+
Dir["#{@component_dir}/*.config.yaml"].each do |config_file|
|
42
|
+
puts "Loading config for #{@name}:\n\tread #{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
|
+
# load extensions
|
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
|
+
# evaluate components template
|
61
|
+
# @param [Hash] config_override
|
62
|
+
def load(config_override = nil)
|
63
|
+
if @component_dir.start_with? 'http'
|
64
|
+
raise StandardError, 'http(s) sources not supported yet'
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
@highlander_dsl_path = "#{@component_dir}/#{@template.template_name}.highlander.rb"
|
69
|
+
@cfndsl_path = "#{@component_dir}/#{@template.template_name}.cfndsl.rb"
|
70
|
+
candidate_mappings_path = "#{@component_dir}/*.mappings.yaml"
|
71
|
+
candidate_dynamic_mappings_path = "#{@component_dir}/#{@template.template_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
|
+
@config['component_name'] = @name
|
83
|
+
@config['template_name'] = @template.template_name
|
84
|
+
@config['template_version'] = @template.template_version
|
85
|
+
# allow override of components
|
86
|
+
# config_override.each do |key, value|
|
87
|
+
# @config[key] = value
|
88
|
+
# end unless config_override.nil?
|
89
|
+
|
90
|
+
Dir[candidate_mappings_path].each do |mapping_file|
|
91
|
+
mappings = YAML.load(File.read(mapping_file))
|
92
|
+
@component_files << mapping_file
|
93
|
+
mappings.each do |name, map|
|
94
|
+
@mappings[name] = map
|
95
|
+
end unless mappings.nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
if File.exist? candidate_dynamic_mappings_path
|
99
|
+
require candidate_dynamic_mappings_path
|
100
|
+
@component_files << candidate_dynamic_mappings_path
|
101
|
+
end
|
102
|
+
|
103
|
+
# 1st pass - parse the file
|
104
|
+
@component_files << @highlander_dsl_path
|
105
|
+
@highlander_dsl = eval(File.read(@highlander_dsl_path), binding)
|
106
|
+
# set version if not defined
|
107
|
+
@highlander_dsl.ComponentVersion(@version) unless @version.nil?
|
108
|
+
|
109
|
+
|
110
|
+
if @highlander_dsl.description.nil?
|
111
|
+
if template.template_name == @name
|
112
|
+
description = "#{@name}@#{template.template_version} - v#{@highlander_dsl.version}"
|
113
|
+
else
|
114
|
+
description = "#{@name} - v#{@highlander_dsl.version}"
|
115
|
+
description += " (#{template.template_name}@#{template.template_version})"
|
116
|
+
end
|
117
|
+
|
118
|
+
@highlander_dsl.Description(description)
|
119
|
+
end
|
120
|
+
|
121
|
+
# set (override) distribution options
|
122
|
+
@highlander_dsl.DistributionBucket(@distribution_bucket) unless @distribution_bucket.nil?
|
123
|
+
@highlander_dsl.DistributionPrefix(@distribution_prefix) unless @distribution_prefix.nil?
|
124
|
+
|
125
|
+
if File.exist? @cfndsl_path
|
126
|
+
@component_files << @cfndsl_path
|
127
|
+
@cfndsl_content = File.read(@cfndsl_path)
|
128
|
+
@cfndsl_content.strip!
|
129
|
+
# if there is CloudFormation do [content] end extract only contents
|
130
|
+
### Regex \s is whitespace
|
131
|
+
match_data = /^CloudFormation do\s(.*)end\s?$/m.match(@cfndsl_content)
|
132
|
+
if not match_data.nil?
|
133
|
+
@cfndsl_content = match_data[1]
|
134
|
+
end
|
135
|
+
|
136
|
+
else
|
137
|
+
@cfndsl_content = ''
|
138
|
+
end
|
139
|
+
|
140
|
+
loadDepandantExt()
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Highlander
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
class TemplateMetadata
|
6
|
+
|
7
|
+
@template_name
|
8
|
+
@template_version
|
9
|
+
@template_location
|
10
|
+
|
11
|
+
attr_reader :template_location,
|
12
|
+
:template_version,
|
13
|
+
:template_name
|
14
|
+
|
15
|
+
def initialize(template_name:, template_version:, template_location:)
|
16
|
+
@template_name = template_name
|
17
|
+
@template_version = template_version
|
18
|
+
@template_location = template_location
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/highlander.publisher.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfhighlander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.1.alpha.
|
4
|
+
version: 0.2.1.alpha.32
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nikola Tosic
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-06-
|
12
|
+
date: 2018-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: highline
|
@@ -249,8 +249,11 @@ files:
|
|
249
249
|
- lib/highlander.dsl.params.rb
|
250
250
|
- lib/highlander.dsl.rb
|
251
251
|
- lib/highlander.factory.rb
|
252
|
+
- lib/highlander.factory.templatefinder.rb
|
252
253
|
- lib/highlander.helper.rb
|
253
254
|
- lib/highlander.mapproviders.rb
|
255
|
+
- lib/highlander.model.component.rb
|
256
|
+
- lib/highlander.model.templatemeta.rb
|
254
257
|
- lib/highlander.publisher.rb
|
255
258
|
- lib/highlander.validator.rb
|
256
259
|
- lib/util/zip.util.rb
|