blufin-lib 1.6.1 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/blufin-lib.rb +1 -0
- data/lib/core/aws.rb +44 -0
- data/lib/core/projects.rb +137 -172
- data/lib/core/strings.rb +6 -2
- data/lib/core/terminal.rb +50 -45
- data/lib/core/tools.rb +36 -0
- data/lib/core/validate.rb +1 -1
- data/lib/version.rb +1 -1
- data/opt/awx/project-schema.yml +68 -66
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e5791167393d7968f07af6998fd44e3e01682b0
|
4
|
+
data.tar.gz: 7d86180cd83561d70d074d2d1c7e7b4d10145e71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 466b61784d9767ca6d7e32b4277f809dd7b1b79c6f97b9dc183274392d064a102451abbdaf20b9c710223b9c5565b4ed223db7b79f242081ffb7540fc3786ae3
|
7
|
+
data.tar.gz: d3bc26127ee11355383cf88b8a3eca92ab406196cd449ddfbd2430dd9f4235795cb3bd8bcec80e91bb47081ecd0d1ce47094895247f2e48b6d13f8d9e5aa6f18
|
data/lib/blufin-lib.rb
CHANGED
data/lib/core/aws.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Blufin
|
2
|
+
|
3
|
+
module AWS
|
4
|
+
|
5
|
+
# Pulls a file from S3 and saves it to the /tmp folder.
|
6
|
+
# To avoid making multiple calls, caching is turned on by default.
|
7
|
+
# @return string (path to tmp file).
|
8
|
+
def self.download_s3_data(bucket_name, bucket_path, file: nil, profile: nil, region: nil, use_cache: true)
|
9
|
+
raise RuntimeError, 'profile cannot be nil.' if profile.nil?
|
10
|
+
raise RuntimeError, 'region cannot be nil.' if region.nil?
|
11
|
+
bucket_path = Blufin::Strings::remove_surrounding_slashes(bucket_path).strip
|
12
|
+
bucket_path_tmp = bucket_path.length > 0 ? "-#{bucket_path.gsub('/', '-')}" : ''
|
13
|
+
bucket_path_s3 = bucket_path.length > 0 ? "/#{bucket_path}" : ''
|
14
|
+
unless file.nil?
|
15
|
+
bucket_path_tmp = "#{bucket_path_tmp}-#{file}"
|
16
|
+
bucket_path_s3 = "#{bucket_path_s3}/#{file}"
|
17
|
+
end
|
18
|
+
tmp_location = "/tmp/awx-s3-cache-#{bucket_name}#{bucket_path_tmp}"
|
19
|
+
# If path/file exists and we're using cached values, simply return.
|
20
|
+
if file.nil?
|
21
|
+
return tmp_location if Blufin::Files::path_exists(tmp_location) && use_cache && Blufin::Files::get_files_in_dir(tmp_location).any?
|
22
|
+
else
|
23
|
+
return tmp_location if Blufin::Files::file_exists(tmp_location) && use_cache
|
24
|
+
end
|
25
|
+
begin
|
26
|
+
# Clear out all (possibly stale) files.
|
27
|
+
raise RuntimeError unless Blufin::Terminal::execute_proc("Wiping temp-folder: #{Blufin::Terminal::format_directory(tmp_location)}", Proc.new {
|
28
|
+
system("rm -rf #{tmp_location}") if file.nil?
|
29
|
+
system("rm #{tmp_location}") unless file.nil?
|
30
|
+
Blufin::Files::create_directory(tmp_location)
|
31
|
+
}, verbose: true)
|
32
|
+
raise RuntimeError unless Blufin::Terminal::execute("aws s3 cp s3://#{bucket_name}#{bucket_path_s3} #{tmp_location} --recursive --profile #{profile} --region #{region}", verbose: true)
|
33
|
+
tmp_location
|
34
|
+
rescue
|
35
|
+
system("rm -rf #{tmp_location}") if file.nil?
|
36
|
+
system("rm #{tmp_location}") unless file.nil?
|
37
|
+
Blufin::Terminal::error("Unable to download from S3 bucket: #{Blufin::Terminal::format_highlight("s3://#{bucket_name}#{bucket_path_s3}")}", "Either the bucket doesn't exist, you don't have permissions or something else is wrong...", true, false)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/core/projects.rb
CHANGED
@@ -2,79 +2,75 @@ module Blufin
|
|
2
2
|
|
3
3
|
class Projects
|
4
4
|
|
5
|
-
SCHEMA_FILE
|
6
|
-
SCRIPT_RUN
|
7
|
-
SCRIPT_TEST
|
8
|
-
SCRIPT_BUILD
|
9
|
-
SCRIPT_DEPLOY
|
10
|
-
RUN_SCRIPTS
|
11
|
-
TEST_SCRIPTS
|
12
|
-
BUILD_SCRIPTS
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
ALIAS = 'Alias'
|
33
|
-
DOMAIN = 'Domain'
|
5
|
+
SCHEMA_FILE = "#{Blufin::Base::get_base_path}#{Blufin::Base::OPT_PATH}/awx/project-schema.yml"
|
6
|
+
SCRIPT_RUN = 'run'
|
7
|
+
SCRIPT_TEST = 'test'
|
8
|
+
SCRIPT_BUILD = 'build'
|
9
|
+
SCRIPT_DEPLOY = 'deploy'
|
10
|
+
RUN_SCRIPTS = 'RunScripts'
|
11
|
+
TEST_SCRIPTS = 'TestScripts'
|
12
|
+
BUILD_SCRIPTS = 'BuildScripts'
|
13
|
+
ID = 'Id'
|
14
|
+
PROJECT_ID = 'ProjectId'
|
15
|
+
PROJECT = 'Project'
|
16
|
+
TYPE = 'Type'
|
17
|
+
REPOSITORY = 'Repository'
|
18
|
+
DEPLOYMENT = 'Deployment'
|
19
|
+
DEPLOYMENT_BUCKET = 'Bucket'
|
20
|
+
DEPLOYMENT_FILES = 'Files'
|
21
|
+
RUN = 'Run'
|
22
|
+
TEST = 'Test'
|
23
|
+
BUILD = 'Build'
|
24
|
+
COMMANDS = 'Commands'
|
25
|
+
API = 'API'
|
26
|
+
CRON = 'Cron'
|
27
|
+
WORKER = 'Worker'
|
28
|
+
LAMBDA = 'Lambda'
|
29
|
+
TITLE = 'Title'
|
30
|
+
ALIAS = 'Alias'
|
31
|
+
DOMAIN = 'Domain'
|
34
32
|
PROJECT_NAME_PASCAL_CASE = 'ProjectNamePascalCase'
|
35
|
-
PROJECT_NAME
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
PROJECT_NAME = 'ProjectName'
|
34
|
+
PORT = 'Port'
|
35
|
+
PORTS = 'Ports'
|
36
|
+
STAGE = 'Stage'
|
37
|
+
TYPE_ALEXA = 'alexa'
|
38
|
+
TYPE_API = 'api'
|
39
|
+
TYPE_LAMBDA = 'lambda'
|
40
|
+
TYPE_UI = 'ui'
|
41
|
+
VALID_TYPES = [
|
41
42
|
TYPE_ALEXA,
|
42
43
|
TYPE_API,
|
43
44
|
TYPE_LAMBDA,
|
44
45
|
TYPE_UI,
|
45
46
|
]
|
46
47
|
|
47
|
-
@@projects
|
48
|
+
@@projects = nil
|
48
49
|
@@project_names = []
|
49
|
-
@@scripts
|
50
|
-
@@
|
51
|
-
@@
|
52
|
-
@@environments = []
|
50
|
+
@@scripts = nil
|
51
|
+
@@apis = nil
|
52
|
+
@@lambdas = nil
|
53
53
|
|
54
|
-
# Takes a Hash that
|
54
|
+
# Takes a Hash that needs to have a 'Projects' key.
|
55
55
|
# This can come from both .awx.yml['Profiles'] or .blufin.yml (root).
|
56
56
|
# @return void
|
57
|
-
def self.init(
|
57
|
+
def self.init(projects)
|
58
58
|
raise RuntimeError, 'Cannot run Blufin::Projects::init() more than once.' unless @@projects.nil? && @@scripts.nil?
|
59
|
+
raise RuntimeError, "Need either a Local or S3Bucket key, found neither: #{projects.keys}" unless projects.has_key?('Local') || projects.has_key?('S3Bucket')
|
59
60
|
@@projects = {}
|
60
|
-
@@scripts
|
61
|
-
if
|
62
|
-
|
63
|
-
# Throw error if
|
64
|
-
Blufin::Terminal::error("
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
Blufin::Terminal::error("Cannot find source file: #{Blufin::Terminal::format_directory(source_file)}") unless Blufin::Files::file_exists(source_file)
|
69
|
-
# Validate the source file against the expected schema.
|
70
|
-
process_source_file(source_file)
|
71
|
-
elsif projects.has_key?('S3Bucket')
|
61
|
+
@@scripts = {}
|
62
|
+
if projects.has_key?('Local')
|
63
|
+
source_file = File.expand_path(projects['Local']['File'])
|
64
|
+
# Throw error if source file doesn't exist.
|
65
|
+
Blufin::Terminal::error("Cannot find source file: #{Blufin::Terminal::format_directory(source_file)}") unless Blufin::Files::file_exists(source_file)
|
66
|
+
# Validate the source file against the expected schema.
|
67
|
+
process_source_file(source_file)
|
68
|
+
elsif projects.has_key?('S3Bucket')
|
72
69
|
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
# TODO - Finish this once we start running this on an EC2 instance (build/deploy server).
|
71
|
+
# TODO - Whatever file we validate should be available on disk locally.
|
72
|
+
# TODO - If the source is an S3 bucket, pull it down into a /tmp folder (on EC2 instance) and validate from there.
|
76
73
|
|
77
|
-
end
|
78
74
|
end
|
79
75
|
end
|
80
76
|
|
@@ -102,38 +98,10 @@ module Blufin
|
|
102
98
|
@@apis
|
103
99
|
end
|
104
100
|
|
105
|
-
# Gets
|
106
|
-
# @return Array
|
107
|
-
def self.get_environments
|
108
|
-
@@environments
|
109
|
-
end
|
110
|
-
|
111
|
-
# Get matching deployments for parameters.
|
101
|
+
# Gets Lambda(s).
|
112
102
|
# @return Hash
|
113
|
-
def self.
|
114
|
-
|
115
|
-
@@deployments = {}
|
116
|
-
if @@projects.is_a?(Hash) && @@projects.has_key?(project)
|
117
|
-
project = @@projects[project]
|
118
|
-
project.each do |deployment_id, data|
|
119
|
-
if data.is_a?(Hash) && data.has_key?(SERVERS)
|
120
|
-
servers = data[SERVERS]
|
121
|
-
if servers.is_a?(Array)
|
122
|
-
servers.each do |server|
|
123
|
-
if server.has_key?(REGION) && server[REGION] == region
|
124
|
-
if server.has_key?(STACK) && server[STACK] == stack
|
125
|
-
if server.has_key?(ENVIRONMENTS) && server[ENVIRONMENTS].include?(environment)
|
126
|
-
@@deployments[deployment_id] = data
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
@@deployments
|
103
|
+
def self.get_lambdas
|
104
|
+
@@lambdas
|
137
105
|
end
|
138
106
|
|
139
107
|
# Maps root-level property to enum.
|
@@ -145,8 +113,6 @@ module Blufin
|
|
145
113
|
return TEST_SCRIPTS
|
146
114
|
elsif [BUILD_SCRIPTS, BUILD].include?(script_type)
|
147
115
|
return BUILD_SCRIPTS
|
148
|
-
elsif [DEPLOY_SCRIPTS, DEPLOY].include?(script_type)
|
149
|
-
return DEPLOY_SCRIPTS
|
150
116
|
else
|
151
117
|
raise RuntimeError, "Unhandled script type: #{script_type}"
|
152
118
|
end
|
@@ -175,13 +141,13 @@ module Blufin
|
|
175
141
|
end
|
176
142
|
|
177
143
|
# Buffer script(s).
|
178
|
-
[RUN_SCRIPTS, TEST_SCRIPTS, BUILD_SCRIPTS
|
144
|
+
[RUN_SCRIPTS, TEST_SCRIPTS, BUILD_SCRIPTS].each do |script_type|
|
179
145
|
if file_parsed.has_key?(script_type)
|
180
146
|
if file_parsed[script_type].is_a?(Array)
|
181
|
-
script_key
|
147
|
+
script_key = script_key_mapper(script_type)
|
182
148
|
@@scripts[script_key] = {} unless @@scripts.has_key?(script_key)
|
183
149
|
file_parsed[script_type].each do |script|
|
184
|
-
script_id = script[
|
150
|
+
script_id = script[ID]
|
185
151
|
# Throw error if duplicate script is found for type.
|
186
152
|
Blufin::Terminal::error("#{Blufin::Terminal::format_highlight("#{script_type} - #{script_id}")} \xe2\x80\x94 Duplicate script found: #{Blufin::Terminal::format_invalid(script_id)}") if @@scripts[script_key].has_key?(script_id)
|
187
153
|
@@scripts[script_key][script_id] = script
|
@@ -205,112 +171,102 @@ module Blufin
|
|
205
171
|
file_parsed['Projects'].each do |project|
|
206
172
|
# Validate keys are in specific order.
|
207
173
|
expected = {
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
SERVERS => false,
|
219
|
-
API => false
|
174
|
+
PROJECT_ID => true,
|
175
|
+
PROJECT => true,
|
176
|
+
TYPE => true,
|
177
|
+
REPOSITORY => true,
|
178
|
+
RUN => false,
|
179
|
+
TEST => false,
|
180
|
+
BUILD => false,
|
181
|
+
API => false,
|
182
|
+
LAMBDA => false,
|
183
|
+
DEPLOYMENT => false
|
220
184
|
}
|
221
185
|
Blufin::Validate::assert_valid_keys(expected, project.keys, source_file)
|
222
|
-
project_id
|
186
|
+
project_id = project[PROJECT_ID]
|
223
187
|
project_name = project[PROJECT]
|
224
188
|
project_type = project[TYPE]
|
225
|
-
|
226
189
|
@@project_names << project_name
|
227
|
-
|
228
190
|
# Validate Type.
|
229
191
|
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Invalid Project Type: #{Blufin::Terminal::format_invalid(project_type)}. Valid types are:", VALID_TYPES, true) unless VALID_TYPES.include?(project_type)
|
230
192
|
# Validate Script(s).
|
231
|
-
[RUN, TEST, BUILD
|
193
|
+
[RUN, TEST, BUILD].each do |script_type|
|
232
194
|
if project.has_key?(script_type)
|
233
195
|
# Validate the LAMBDA functions don't need build scripts.
|
234
|
-
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Project type: #{Blufin::Terminal::format_highlight(TYPE_LAMBDA)}
|
235
|
-
if project[script_type].is_a?(
|
236
|
-
script_key
|
196
|
+
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Project type: #{Blufin::Terminal::format_highlight(TYPE_LAMBDA)} does not require #{Blufin::Terminal::format_invalid(script_type)} script(s).", 'This type of project does not support this.', true) if [BUILD].include?(script_type) && project_type == TYPE_LAMBDA
|
197
|
+
if project[script_type].is_a?(Hash)
|
198
|
+
script_key = script_key_mapper(script_type)
|
237
199
|
valid_scripts = []
|
238
200
|
valid_scripts = @@scripts[script_key].keys if @@scripts.has_key?(script_key)
|
239
|
-
project[script_type]
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
end
|
201
|
+
script = project[script_type]
|
202
|
+
script_name = script['Script']
|
203
|
+
unless valid_scripts.include?(script_name)
|
204
|
+
error = valid_scripts.any? ? 'Valid values are:' : "There currently are no #{script_key} script(s) defined."
|
205
|
+
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 #{Blufin::Terminal::format_highlight(script_type)} \xe2\x80\x94 Invalid script reference: #{Blufin::Terminal::format_invalid(script_name)}. #{error}", valid_scripts)
|
245
206
|
end
|
246
207
|
end
|
247
208
|
end
|
248
209
|
end
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
targets[environment] = {} unless targets.has_key?(environment)
|
258
|
-
targets[environment] = {
|
259
|
-
:region => region,
|
260
|
-
:stack => stack,
|
261
|
-
}
|
262
|
-
@@environments << environment
|
263
|
-
end
|
264
|
-
end
|
265
|
-
project[TARGETS] = targets
|
210
|
+
|
211
|
+
# Validate Deployment property.
|
212
|
+
if project.has_key?(DEPLOYMENT)
|
213
|
+
expected = {
|
214
|
+
DEPLOYMENT_BUCKET => true,
|
215
|
+
DEPLOYMENT_FILES => true
|
216
|
+
}
|
217
|
+
Blufin::Validate::assert_valid_keys(expected, project[DEPLOYMENT].keys, source_file)
|
266
218
|
end
|
267
|
-
|
219
|
+
|
220
|
+
# Validate API property.
|
268
221
|
if project_type == TYPE_API
|
269
|
-
# Make sure we have the API
|
222
|
+
# Make sure we have the API property.
|
270
223
|
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Missing property: #{Blufin::Terminal::format_highlight(API)}", "This property is required for project(s) with type: #{API}", true) unless project.has_key?(API)
|
271
|
-
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Missing property: #{Blufin::Terminal::format_highlight(PORT_RANGE)}", "This property is required for project(s) with type: #{API}", true) unless project.has_key?(PORT_RANGE)
|
272
224
|
# Validate keys are in specific order.
|
273
225
|
expected = {
|
274
|
-
TITLE
|
275
|
-
ALIAS
|
276
|
-
DOMAIN
|
277
|
-
PROJECT_NAME
|
278
|
-
PROJECT_NAME_PASCAL_CASE => true
|
226
|
+
TITLE => true,
|
227
|
+
ALIAS => true,
|
228
|
+
DOMAIN => true,
|
229
|
+
PROJECT_NAME => true,
|
230
|
+
PROJECT_NAME_PASCAL_CASE => true,
|
231
|
+
PORTS => true
|
279
232
|
}
|
280
233
|
Blufin::Validate::assert_valid_keys(expected, project[API].keys, source_file)
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
ALIAS => project[API][ALIAS],
|
286
|
-
PROJECT_NAME => project[API][PROJECT_NAME],
|
287
|
-
PROJECT_NAME_PASCAL_CASE => project[API][PROJECT_NAME_PASCAL_CASE],
|
288
|
-
DOMAIN => project[API][DOMAIN],
|
289
|
-
PORT_RANGE => project[PORT_RANGE]
|
234
|
+
expected_ports = {
|
235
|
+
API => true,
|
236
|
+
CRON => true,
|
237
|
+
WORKER => true
|
290
238
|
}
|
239
|
+
Blufin::Validate::assert_valid_keys(expected_ports, project[API][PORTS].keys, source_file)
|
240
|
+
validate_ports([project[API][PORTS][API], project[API][PORTS][CRON], project[API][PORTS][WORKER]], project_id, used_ports)
|
241
|
+
# Add ports to used_ports.
|
242
|
+
used_ports[project[API][PORTS][API]] = project_id
|
243
|
+
used_ports[project[API][PORTS][CRON]] = project_id
|
244
|
+
used_ports[project[API][PORTS][WORKER]] = project_id
|
245
|
+
@@apis = {} if @@apis.nil?
|
246
|
+
@@apis[project[PROJECT_ID]] = project[API]
|
291
247
|
else
|
292
248
|
# Make sure we DON'T have the API key.
|
293
249
|
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Property not supported: #{Blufin::Terminal::format_invalid(API)}", "This property is only allowed for project(s) with type: #{API}", true) if project.has_key?(API)
|
294
250
|
end
|
295
251
|
|
296
|
-
# Validate
|
297
|
-
if
|
298
|
-
|
299
|
-
#
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
Blufin::
|
306
|
-
|
307
|
-
(prs[0].to_i..prs[1].to_i).each do |i|
|
308
|
-
if used_ports.has_key?(i)
|
309
|
-
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Port overlap detected for range: #{Blufin::Terminal::format_invalid(port_range)}", ["The conflicting project is: #{used_ports[i]}"])
|
310
|
-
end
|
311
|
-
end
|
252
|
+
# Validate Lambda property.
|
253
|
+
if project_type == TYPE_LAMBDA
|
254
|
+
# Make sure we have the Lambda
|
255
|
+
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Missing property: #{Blufin::Terminal::format_highlight(LAMBDA)}", "This property is required for project(s) with type: #{LAMBDA}", true) unless project.has_key?(LAMBDA)
|
256
|
+
# Validate keys are in specific order.
|
257
|
+
expected = {
|
258
|
+
PORT => true,
|
259
|
+
STAGE => true
|
260
|
+
}
|
261
|
+
Blufin::Validate::assert_valid_keys(expected, project[LAMBDA].keys, source_file)
|
262
|
+
validate_ports([project[LAMBDA][PORT]], project_id, used_ports)
|
312
263
|
# Add ports to used_ports.
|
313
|
-
|
264
|
+
used_ports[project[LAMBDA][PORT]] = project_id
|
265
|
+
@@lambdas = {} if @@lambdas.nil?
|
266
|
+
@@lambdas[project[PROJECT_ID]] = project[LAMBDA]
|
267
|
+
else
|
268
|
+
# Make sure we DON'T have the Lambda key.
|
269
|
+
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Property not supported: #{Blufin::Terminal::format_invalid(LAMBDA)}", "This property is only allowed for project(s) with type: #{LAMBDA}", true) if project.has_key?(LAMBDA)
|
314
270
|
end
|
315
271
|
|
316
272
|
@@projects[project_name] = {} unless @@projects.has_key?(project_name)
|
@@ -318,9 +274,18 @@ module Blufin
|
|
318
274
|
@@projects[project_name][project_id] = project
|
319
275
|
|
320
276
|
end
|
277
|
+
@@project_names.uniq!
|
278
|
+
@@project_names.sort!
|
279
|
+
end
|
280
|
+
end
|
321
281
|
|
322
|
-
|
323
|
-
|
282
|
+
# Validate the ports. Make sure none of the ports conflict with other projects.
|
283
|
+
# @return void
|
284
|
+
def self.validate_ports(ports, project_id, used_ports)
|
285
|
+
ports.each do |port|
|
286
|
+
if used_ports.has_key?(port)
|
287
|
+
Blufin::Terminal::error("#{project_id} \xe2\x80\x94 Duplicate port detected: #{Blufin::Terminal::format_invalid(port)} ", ["The conflicting project is: #{Blufin::Terminal::format_highlight(used_ports[port])}"])
|
288
|
+
end
|
324
289
|
|
325
290
|
end
|
326
291
|
|
data/lib/core/strings.rb
CHANGED
@@ -89,8 +89,12 @@ module Blufin
|
|
89
89
|
# Generate Random string.
|
90
90
|
# Currently returns something like: 1ec6c763
|
91
91
|
# @return String
|
92
|
-
def self.random_string
|
93
|
-
|
92
|
+
def self.random_string(x = 1)
|
93
|
+
rs = ''
|
94
|
+
x.times do
|
95
|
+
rs = "#{rs}#{SecureRandom.uuid.split('-')[0].downcase}"
|
96
|
+
end
|
97
|
+
rs
|
94
98
|
end
|
95
99
|
|
96
100
|
private
|
data/lib/core/terminal.rb
CHANGED
@@ -12,15 +12,15 @@ module Blufin
|
|
12
12
|
|
13
13
|
extend Columnist
|
14
14
|
|
15
|
-
MSG_INFO
|
16
|
-
MSG_WARNING
|
17
|
-
MSG_ERROR
|
18
|
-
MSG_TODO
|
19
|
-
MSG_AUTOMATIC
|
20
|
-
MSG_GENERATED
|
21
|
-
MSG_PROCESSED
|
22
|
-
MSG_PROGRESS
|
23
|
-
MSG_CUSTOM
|
15
|
+
MSG_INFO = 'info'
|
16
|
+
MSG_WARNING = 'warning'
|
17
|
+
MSG_ERROR = 'error'
|
18
|
+
MSG_TODO = 'todo'
|
19
|
+
MSG_AUTOMATIC = 'automatic'
|
20
|
+
MSG_GENERATED = 'generated'
|
21
|
+
MSG_PROCESSED = 'processed'
|
22
|
+
MSG_PROGRESS = 'progress'
|
23
|
+
MSG_CUSTOM = 'custom'
|
24
24
|
MSG_CUSTOM_AUTO_PAD = 'custom_auto_pad'
|
25
25
|
|
26
26
|
# Runs a series of commands in the terminal.
|
@@ -79,8 +79,8 @@ module Blufin
|
|
79
79
|
# See: https://github.com/piotrmurach/tty-spinner/blob/master/lib/tty/spinner/formats.rb (for spinner options).
|
80
80
|
# @return void
|
81
81
|
def self.execute(command, path = nil, capture: false, verbose: true, text: nil)
|
82
|
-
text
|
83
|
-
t1
|
82
|
+
text = text.is_a?(String) ? text : command
|
83
|
+
t1 = Time.now
|
84
84
|
spinner = TTY::Spinner.new("[:spinner] \x1B[38;5;208m#{text}#{!path.nil? ? " \x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;240m#{path}" : nil}\x1B[0m", format: :dots) if verbose
|
85
85
|
spinner.auto_spin if verbose
|
86
86
|
path = File.expand_path('~/') if path.nil?
|
@@ -89,7 +89,7 @@ module Blufin
|
|
89
89
|
else
|
90
90
|
res = system("cd #{path} && #{command} > /tmp/execute-output")
|
91
91
|
end
|
92
|
-
t2
|
92
|
+
t2 = Time.now
|
93
93
|
delta = "#{'%.3f' % (t2 - t1).abs}s"
|
94
94
|
if res || capture
|
95
95
|
spinner.success("\x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;46mComplete \x1B[38;5;240m(#{delta})\x1B[0m\x1B[0m") if verbose
|
@@ -108,12 +108,12 @@ module Blufin
|
|
108
108
|
def self.execute_proc(title, proc, verbose: true)
|
109
109
|
raise RuntimeError, "Expected String, instead got:#{title.class}" unless title.is_a?(String)
|
110
110
|
raise RuntimeError, "Expected proc to be an instance of Proc, instead got: #{proc.class}" unless proc.is_a?(Proc)
|
111
|
-
t1
|
111
|
+
t1 = Time.now
|
112
112
|
spinner = nil
|
113
113
|
spinner = TTY::Spinner.new("[:spinner] \x1B[38;5;208m#{title}\x1B[0m", format: :dots) if verbose
|
114
114
|
spinner.auto_spin if verbose
|
115
|
-
res
|
116
|
-
t2
|
115
|
+
res = proc.call
|
116
|
+
t2 = Time.now
|
117
117
|
delta = "#{'%.3f' % (t2 - t1).abs}s"
|
118
118
|
spinner.success("\x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;46mComplete \x1B[38;5;240m(#{delta})\x1B[0m\x1B[0m") if verbose && res
|
119
119
|
spinner.error("\x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;196mFailed (#{delta})\x1B[0m") if verbose && !res
|
@@ -159,7 +159,7 @@ module Blufin
|
|
159
159
|
# Displays error and exits script by default.
|
160
160
|
# @return void
|
161
161
|
def self.abort(title = nil, message = nil, exit_script = true, preceding_blank_line = false)
|
162
|
-
title
|
162
|
+
title = 'Abandon ship!' if title.nil?
|
163
163
|
message = "You have chosen to \x1B[38;5;196mABORT\x1B[38;5;240m the script." if message.nil?
|
164
164
|
Blufin::Terminal::error(title, message, exit_script, preceding_blank_line, 'ABORT')
|
165
165
|
end
|
@@ -250,7 +250,7 @@ module Blufin
|
|
250
250
|
# Returns command name in consistent, uniform manner.
|
251
251
|
# @return String
|
252
252
|
def self.format_command(command_name)
|
253
|
-
"\x1B[38;5;
|
253
|
+
"\x1B[38;5;70m$ \x1B[38;5;240m#{command_name}\x1B[0m"
|
254
254
|
end
|
255
255
|
|
256
256
|
# Returns directory name in consistent, uniform manner.
|
@@ -284,16 +284,16 @@ module Blufin
|
|
284
284
|
def self.format_highlight(highlighted_text, capitalize = false, target: nil)
|
285
285
|
case target
|
286
286
|
when 'cf' # CloudFormation
|
287
|
-
color
|
287
|
+
color = 82
|
288
288
|
color_end = "\x1B[38;5;246m"
|
289
289
|
when 'cf-ctt' # CloudFormation (Creation Time Title)
|
290
|
-
color
|
290
|
+
color = 196
|
291
291
|
color_end = "\x1B[38;5;246m"
|
292
292
|
when 'cf-ct' # CloudFormation (Creation Time)
|
293
|
-
color
|
293
|
+
color = 82
|
294
294
|
color_end = "\x1B[38;5;246m"
|
295
295
|
else
|
296
|
-
color
|
296
|
+
color = 117
|
297
297
|
color_end = "\x1B[0m"
|
298
298
|
end
|
299
299
|
if capitalize
|
@@ -326,7 +326,7 @@ module Blufin
|
|
326
326
|
# Gives a prompt where 'y/Y' will return TRUE, 'n/N' will return false, and ANY other key will do nothing.
|
327
327
|
# @return void
|
328
328
|
def self.prompt_yes_no(title = nil, message = nil, confirmation_message = nil, preceding_blank_line = true)
|
329
|
-
title
|
329
|
+
title = 'Please confirm YES or NO.' if title.nil?
|
330
330
|
confirmation_message = 'Would you like to continue?' if confirmation_message.nil?
|
331
331
|
puts if preceding_blank_line
|
332
332
|
puts " \x1B[38;5;231m\x1B[48;5;55m Confirm \x1B[0m #{title.nil? ? '' : "\xe2\x86\x92 "}#{title}\n"
|
@@ -423,16 +423,26 @@ module Blufin
|
|
423
423
|
if options[0].is_a?(String)
|
424
424
|
prompt.select(display_prompt_text(question), options, per_page: per_page)
|
425
425
|
elsif options[0].is_a?(Hash)
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
426
|
+
options_fixed = []
|
427
|
+
options.each do |option|
|
428
|
+
raise RuntimeError, "Expected option to be Hash, instead got: (#{option.class}) #{option.inspect}" unless option.is_a?(Hash)
|
429
|
+
raise RuntimeError, 'Option is missing key => :text' unless option.has_key?(:text)
|
430
|
+
raise RuntimeError, 'Option is missing key => :value' unless option.has_key?(:value)
|
431
|
+
raise RuntimeError, "Expected :disabled option to be String, instead got: #{option[:disabled].class}" if option.has_key?(:disabled) && !option[:disabled].is_a?(String) && !option[:disabled].nil?
|
432
|
+
v = option[:value]
|
433
|
+
v = 'true' if option[:value].is_a?(TrueClass)
|
434
|
+
v = 'false' if option[:value].is_a?(FalseClass)
|
435
|
+
options_fixed << {:text => option[:text], :value => v}
|
436
|
+
end
|
437
|
+
result = prompt.select(display_prompt_text(question), per_page: per_page) do |menu|
|
438
|
+
options_fixed.each do |option|
|
432
439
|
menu.choice option[:text], option[:value] unless option.has_key?(:disabled)
|
433
440
|
menu.choice option[:text], option[:value], disabled: "\x1B[38;5;196m#{option[:disabled]}\x1B[0m" if option.has_key?(:disabled)
|
434
441
|
end
|
435
442
|
end
|
443
|
+
return true if result == 'true'
|
444
|
+
return false if result == 'false'
|
445
|
+
return result
|
436
446
|
else
|
437
447
|
raise RuntimeError, "Expected options Array to consist of either Strings or Hashes, instead got: #{options.inspect}"
|
438
448
|
end
|
@@ -493,8 +503,8 @@ module Blufin
|
|
493
503
|
def self.prompt_expand(question, options)
|
494
504
|
raise RuntimeError, "Expected Array, instead got #{options.class}" unless options.is_a?(Array)
|
495
505
|
options.each do |option|
|
496
|
-
found_key
|
497
|
-
found_name
|
506
|
+
found_key = false
|
507
|
+
found_name = false
|
498
508
|
found_value = false
|
499
509
|
option.each do |k, v|
|
500
510
|
case k
|
@@ -560,11 +570,11 @@ module Blufin
|
|
560
570
|
# @return void
|
561
571
|
def self.print_files_written(array_of_paths_or_files, message = nil, limit = 10, preceding_blank_line = true)
|
562
572
|
raise RuntimeError, "Expected Array of files, instead got: #{array_of_paths_or_files.class}" unless array_of_paths_or_files.is_a?(Array)
|
563
|
-
message
|
564
|
-
limit
|
573
|
+
message = "Wrote the following #{Blufin::Terminal::format_highlight('files/directories')}" if message.nil?
|
574
|
+
limit = limit.nil? ? 99999999999 : limit.to_i
|
565
575
|
file_output = []
|
566
|
-
file_count
|
567
|
-
file_more
|
576
|
+
file_count = 0
|
577
|
+
file_more = 0
|
568
578
|
array_of_paths_or_files.compact!
|
569
579
|
array_of_paths_or_files.sort!
|
570
580
|
array_of_paths_or_files.each do |path_or_file|
|
@@ -594,13 +604,13 @@ module Blufin
|
|
594
604
|
# @return void
|
595
605
|
def self.code_highlight(string, type, indent = 5)
|
596
606
|
raise RuntimeError, "Expected String, instead got:#{string.class}" unless string.is_a?(String)
|
597
|
-
type
|
607
|
+
type = type.downcase
|
598
608
|
types = {
|
599
|
-
'yml'
|
609
|
+
'yml' => Rouge::Lexers::YAML.new,
|
600
610
|
'json' => Rouge::Lexers::JSON.new
|
601
611
|
}
|
602
612
|
raise RuntimeError, "Lexer not defined for type: #{type}" unless types.has_key?(type)
|
603
|
-
repeat
|
613
|
+
repeat = ' ' * indent
|
604
614
|
formatter = Rouge::Formatters::Terminal256.new
|
605
615
|
formatter.format(types[type].lex(string)).split("\n").each do |line|
|
606
616
|
puts "#{repeat}#{line}"
|
@@ -619,14 +629,9 @@ module Blufin
|
|
619
629
|
else
|
620
630
|
messages = message.split("\n")
|
621
631
|
end
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
row do
|
626
|
-
column('', :align => 'left', :width => 4)
|
627
|
-
column("\x1B[38;5;240m#{new_line}\x1B[0m", :align => 'left', :width => 180)
|
628
|
-
end
|
629
|
-
end
|
632
|
+
messages.each do |line|
|
633
|
+
new_line = line.nil? ? '' : line.to_s.gsub("\x1B[0m", "\x1B[38;5;240m")
|
634
|
+
puts " \x1B[38;5;240m#{new_line}\x1B[0m"
|
630
635
|
end
|
631
636
|
puts
|
632
637
|
end
|
data/lib/core/tools.rb
CHANGED
@@ -102,6 +102,42 @@ module Blufin
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
# Returns a value based on OS. If any of the values are nil, throws an Exception.
|
106
|
+
# Linux supports both LINUX and UNIX enums.
|
107
|
+
# @return string
|
108
|
+
def self.value_based_on_os(mac: nil, windows: nil, linux: nil)
|
109
|
+
begin
|
110
|
+
case Blufin::Tools::os
|
111
|
+
when Blufin::Tools::OS_WINDOWS
|
112
|
+
raise RuntimeError if windows.nil?
|
113
|
+
return windows
|
114
|
+
when Blufin::Tools::OS_MAC
|
115
|
+
raise RuntimeError if mac.nil?
|
116
|
+
return mac
|
117
|
+
when Blufin::Tools::OS_LINUX
|
118
|
+
raise RuntimeError if linux.nil?
|
119
|
+
return linux
|
120
|
+
when Blufin::Tools::OS_UNIX
|
121
|
+
raise RuntimeError if linux.nil?
|
122
|
+
return linux
|
123
|
+
else
|
124
|
+
raise RuntimeError
|
125
|
+
end
|
126
|
+
rescue => e
|
127
|
+
Blufin::Terminal::error("This command/operation is not yet supported on: #{Blufin::Terminal::format_highlight(Blufin::Tools::os)}", e.split("\n"), true)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Throws uniform error for non-supported os'.
|
132
|
+
# @return void
|
133
|
+
def self.os_not_supported(array_of_os)
|
134
|
+
raise RuntimeError, "Expected Array, instead got: #{array_of_os.class}" unless array_of_os.is_a?(Array)
|
135
|
+
array_of_os.each { |os| raise RuntimeError, "Unsupported OS value: #{Blufin::Terminal::format_invalid(os)}" unless [OS_MAC, OS_WINDOWS, OS_LINUX, OS_UNIX].include?(os) }
|
136
|
+
current_os = os
|
137
|
+
if array_of_os.include?(current_os)
|
138
|
+
Blufin::Terminal::error("#{Blufin::Terminal::format_highlight(current_os.capitalize)} is not supported to run this command/operation.", 'Someone needs to program it and make it compatible.')
|
139
|
+
end
|
140
|
+
end
|
105
141
|
|
106
142
|
end
|
107
143
|
|
data/lib/core/validate.rb
CHANGED
@@ -9,7 +9,6 @@ module Blufin
|
|
9
9
|
# @return null - If errors, will raise exception.
|
10
10
|
def self.assert_valid_keys(expected, actual, description)
|
11
11
|
raise RuntimeError, "Expected Hash, instead got: #{expected.class}" unless expected.is_a?(Hash)
|
12
|
-
raise RuntimeError, "Expected Array, instead got: #{actual.class}" unless actual.is_a?(Array)
|
13
12
|
errors = []
|
14
13
|
required_keys = []
|
15
14
|
optional_keys = []
|
@@ -48,4 +47,5 @@ module Blufin
|
|
48
47
|
end
|
49
48
|
|
50
49
|
end
|
50
|
+
|
51
51
|
end
|
data/lib/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
BLUFIN_LIB_VERSION = '1.
|
1
|
+
BLUFIN_LIB_VERSION = '1.7.0'
|
data/opt/awx/project-schema.yml
CHANGED
@@ -36,85 +36,66 @@ mapping:
|
|
36
36
|
required: yes
|
37
37
|
sequence:
|
38
38
|
- type: str
|
39
|
-
DeployScripts:
|
40
|
-
type: seq
|
41
|
-
sequence:
|
42
|
-
- type: map
|
43
|
-
mapping:
|
44
|
-
Id:
|
45
|
-
required: yes
|
46
|
-
Commands:
|
47
|
-
type: seq
|
48
|
-
required: yes
|
49
|
-
sequence:
|
50
|
-
- type: str
|
51
39
|
Projects:
|
52
40
|
type: seq
|
53
41
|
required: yes
|
54
42
|
sequence:
|
55
43
|
- type: map
|
56
44
|
mapping:
|
57
|
-
|
58
|
-
required: yes
|
59
|
-
Type:
|
45
|
+
ProjectId:
|
60
46
|
required: yes
|
61
47
|
Project:
|
62
48
|
required: yes
|
63
|
-
|
64
|
-
required: yes
|
65
|
-
RepoPath:
|
49
|
+
Type:
|
66
50
|
required: yes
|
67
|
-
|
51
|
+
Repository:
|
52
|
+
type: map
|
53
|
+
mapping:
|
54
|
+
Local:
|
55
|
+
Remote:
|
56
|
+
required: yes
|
57
|
+
ProjectRoot:
|
58
|
+
required: yes
|
68
59
|
Run:
|
69
|
-
type:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
Script:
|
76
|
-
required: yes
|
60
|
+
type: map
|
61
|
+
mapping:
|
62
|
+
Path:
|
63
|
+
required: yes
|
64
|
+
Script:
|
65
|
+
required: yes
|
77
66
|
Test:
|
78
|
-
type:
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
Script:
|
85
|
-
required: yes
|
67
|
+
type: map
|
68
|
+
mapping:
|
69
|
+
Path:
|
70
|
+
required: yes
|
71
|
+
Script:
|
72
|
+
required: yes
|
86
73
|
Build:
|
87
|
-
type:
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
required: yes
|
113
|
-
Environments:
|
114
|
-
type: seq
|
115
|
-
required: yes
|
116
|
-
sequence:
|
117
|
-
- type: str
|
74
|
+
type: map
|
75
|
+
mapping:
|
76
|
+
Path:
|
77
|
+
required: yes
|
78
|
+
Script:
|
79
|
+
required: yes
|
80
|
+
Deployment:
|
81
|
+
type: map
|
82
|
+
mapping:
|
83
|
+
Bucket:
|
84
|
+
type: map
|
85
|
+
required: yes
|
86
|
+
mapping:
|
87
|
+
Name:
|
88
|
+
required: yes
|
89
|
+
Region:
|
90
|
+
required: yes
|
91
|
+
Files:
|
92
|
+
type: seq
|
93
|
+
required: yes
|
94
|
+
sequence:
|
95
|
+
- type: map
|
96
|
+
mapping:
|
97
|
+
Path:
|
98
|
+
Files:
|
118
99
|
API:
|
119
100
|
type: map
|
120
101
|
mapping:
|
@@ -127,4 +108,25 @@ mapping:
|
|
127
108
|
ProjectName:
|
128
109
|
required: yes
|
129
110
|
ProjectNamePascalCase:
|
111
|
+
required: yes
|
112
|
+
Ports:
|
113
|
+
type: map
|
114
|
+
required: yes
|
115
|
+
mapping:
|
116
|
+
API:
|
117
|
+
type: number
|
118
|
+
required: yes
|
119
|
+
Cron:
|
120
|
+
type: number
|
121
|
+
required: yes
|
122
|
+
Worker:
|
123
|
+
type: number
|
124
|
+
required: yes
|
125
|
+
Lambda:
|
126
|
+
type: map
|
127
|
+
mapping:
|
128
|
+
Port:
|
129
|
+
type: number
|
130
|
+
required: yes
|
131
|
+
Stage:
|
130
132
|
required: yes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blufin-lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Albert Rannetsperger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -130,6 +130,7 @@ extra_rdoc_files: []
|
|
130
130
|
files:
|
131
131
|
- lib/blufin-lib.rb
|
132
132
|
- lib/core/arrays.rb
|
133
|
+
- lib/core/aws.rb
|
133
134
|
- lib/core/base.rb
|
134
135
|
- lib/core/config.rb
|
135
136
|
- lib/core/datetime_utils.rb
|
@@ -158,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
158
159
|
requirements:
|
159
160
|
- - ">="
|
160
161
|
- !ruby/object:Gem::Version
|
161
|
-
version: '2.
|
162
|
+
version: '2.3'
|
162
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
164
|
requirements:
|
164
165
|
- - ">="
|
@@ -166,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
167
|
version: '0'
|
167
168
|
requirements: []
|
168
169
|
rubyforge_project:
|
169
|
-
rubygems_version: 2.
|
170
|
+
rubygems_version: 2.5.1
|
170
171
|
signing_key:
|
171
172
|
specification_version: 4
|
172
173
|
summary: Blufin Lib
|