cfhighlander 0.2.1 → 0.3.0.alpha.1528936037

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,359 +0,0 @@
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