awx 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/aws/aws_cloudformation.rb +3 -27
- data/lib/aws/aws_profile.rb +56 -15
- data/lib/aws/aws_reports.rb +1 -1
- data/lib/awx.rb +3 -1
- data/lib/routes/aws_cloudformation_create.rb +192 -140
- data/lib/routes/aws_list.rb +1 -1
- data/lib/version.rb +1 -1
- data/opt/config/schema.yml +12 -0
- data/opt/config/template.yml +5 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52520a21d53d145c1da6785673db13f6f98bb927
|
4
|
+
data.tar.gz: fd8646cb8f06cf49a0cdda13e29a0dd64b3b7329
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c81bba7df3c682a7b732712f610ba01de5c1d217e61a0da9fe5b4d60286353bbac987539bf36ffc48664610c25da336cd9214b4d76f8cdaa065788fdf9c4e79
|
7
|
+
data.tar.gz: 5b535a761bdc19a239b3eb5f8cb2a401ed9443428461fa0e8381ee701a27bb84f44c0ebf12c88faa0fb8082171c96bd97c436c3156ed164e438b7fd7e734fb9a
|
@@ -14,35 +14,11 @@ module App
|
|
14
14
|
# Uploads a cloudformation template to S3 (so we can create a stack from it).
|
15
15
|
# Returns the S3 URL.
|
16
16
|
# @return string
|
17
|
-
def self.upload_cloudformation_template(
|
18
|
-
source = "#{get_cloudformation_path}/#{template_category}/#{template_name}/template.yml"
|
19
|
-
tmp_file = "/tmp/aws-cf-upload-#{template_category}-#{template_name}-#{Blufin::Strings::random_string}.yml"
|
17
|
+
def self.upload_cloudformation_template(source, category, template)
|
20
18
|
raise RuntimeError, "File does not exist: #{source}" unless Blufin::Files::file_exists(source)
|
19
|
+
tmp_file = "/tmp/aws-cf-upload-#{category}-#{template}-#{Blufin::Strings::random_string}.yml"
|
21
20
|
Blufin::Terminal::execute("cp #{source} #{tmp_file}", text: "Preparing template: \x1B[38;5;240m#{tmp_file}\x1B[0m")
|
22
|
-
|
23
|
-
Blufin::Files::write_line_to_file(tmp_file, "Description: \"#{description.gsub('"', '\"')}\"", /AWSTemplateFormatVersion:\s*("|')?[0-9\-]+("|')?/i)
|
24
|
-
# This block of code removes the 2nd description tag.
|
25
|
-
new_lines = []
|
26
|
-
description_found = false
|
27
|
-
parsing_parameters = true
|
28
|
-
Blufin::Files::read_file(tmp_file).each do |line|
|
29
|
-
line = line.gsub("\n", '')
|
30
|
-
if line.strip =~ /^description:/i && !description_found
|
31
|
-
new_lines << line unless description_found
|
32
|
-
description_found = true
|
33
|
-
else
|
34
|
-
parsing_parameters = true if line.strip =~ /^parameters:$/i
|
35
|
-
if parsing_parameters
|
36
|
-
# AWS Template Anatomy: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html
|
37
|
-
parsing_parameters = false if line.strip =~ /^(Metadata|Mappings|Conditions|Transform|Resources|Outputs)+:$/
|
38
|
-
# This skips all the parameter defaults (as they may contain weird data which won't pass regex validation when initially sent to AWS).
|
39
|
-
next if line.strip =~ /^default:/i && parsing_parameters
|
40
|
-
end
|
41
|
-
new_lines << line
|
42
|
-
end
|
43
|
-
end
|
44
|
-
Blufin::Files::write_file(tmp_file, new_lines)
|
45
|
-
template_filename = "#{template_category}-#{template_name}-#{DateTime.now.strftime('%Y%m%d-%H%M%S')}.yml"
|
21
|
+
template_filename = "#{category}-#{template}-#{DateTime.now.strftime('%Y%m%d-%H%M%S')}.yml"
|
46
22
|
bucket_path = get_s3_bucket_path
|
47
23
|
bucket_path = bucket_path == '' ? '' : "#{bucket_path}/"
|
48
24
|
App::AWSCli::s3_upload(tmp_file, App::AWSProfile::get_profile['CloudFormation']['Uploads']['S3Bucket']['Name'], "#{bucket_path}#{template_filename}")
|
data/lib/aws/aws_profile.rb
CHANGED
@@ -5,6 +5,7 @@ module App
|
|
5
5
|
@@profiles = nil
|
6
6
|
@@profile = nil
|
7
7
|
@@credentials = nil
|
8
|
+
@@ssh_users = nil
|
8
9
|
|
9
10
|
FILE_AWS_CONFIG = File.expand_path('~/.aws/config')
|
10
11
|
FILE_AWS_CREDENTIALS = File.expand_path('~/.aws/credentials')
|
@@ -12,15 +13,17 @@ module App
|
|
12
13
|
PROFILE = 'Profile'
|
13
14
|
PROFILES = 'Profiles'
|
14
15
|
CLOUDFORMATION = 'CloudFormation'
|
16
|
+
SSH_KEYS = 'SSHKeys'
|
15
17
|
|
16
18
|
# Reads the config data and decides what profile to use.
|
17
19
|
# @return void
|
18
20
|
def self.init(config_data)
|
19
21
|
|
20
|
-
raise RuntimeError, 'Cannot run App::AWSProfile::init more than once.' unless @@profiles.nil? && @@profile.nil? && @@credentials.nil?
|
22
|
+
raise RuntimeError, 'Cannot run App::AWSProfile::init more than once.' unless @@profiles.nil? && @@profile.nil? && @@credentials.nil? && @@ssh_users.nil?
|
21
23
|
|
22
|
-
@@profiles
|
23
|
-
@@profile
|
24
|
+
@@profiles = {}
|
25
|
+
@@profile = {}
|
26
|
+
@@ssh_users = {}
|
24
27
|
|
25
28
|
first_key = nil
|
26
29
|
|
@@ -46,7 +49,7 @@ module App
|
|
46
49
|
|
47
50
|
errors = []
|
48
51
|
|
49
|
-
# Validate CloudFormation data (if
|
52
|
+
# Validate CloudFormation data (if exist).
|
50
53
|
if @@profile.has_key?(CLOUDFORMATION)
|
51
54
|
# TODO AWX PROFILE - Must support S3.
|
52
55
|
cloudformation_template_path = @@profile[CLOUDFORMATION]['Templates']['Local']['Path']
|
@@ -60,24 +63,27 @@ module App
|
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
66
|
+
# Validate SSHKeys (if exist).
|
67
|
+
download_s3_ssh_users(true)
|
68
|
+
|
63
69
|
# Check the credentials exist.
|
64
70
|
if Blufin::Files::file_exists(FILE_AWS_CREDENTIALS)
|
65
|
-
@@
|
66
|
-
profile
|
67
|
-
config
|
68
|
-
credentials
|
71
|
+
@@credentials = App::AWSCredentials.new
|
72
|
+
profile = @@profile[PROFILE]
|
73
|
+
config = Blufin::Files::file_exists(FILE_AWS_CONFIG) ? ParseConfig.new(FILE_AWS_CONFIG) : nil
|
74
|
+
credentials = ParseConfig.new(FILE_AWS_CREDENTIALS)
|
69
75
|
unless credentials.params[profile].nil?
|
70
76
|
# Currently not used/required (but here just in case).
|
71
77
|
unless config.nil? || config.params[profile].nil?
|
72
|
-
@@
|
73
|
-
@@
|
78
|
+
@@credentials.region = config.params[profile]['region'] unless config.params[profile]['region'].nil?
|
79
|
+
@@credentials.output = config.params[profile]['output'] unless config.params[profile]['output'].nil?
|
74
80
|
|
75
81
|
end
|
76
|
-
@@
|
77
|
-
@@
|
82
|
+
@@credentials.aws_key = credentials.params[profile]['aws_access_key_id'] unless credentials.params[profile]['aws_access_key_id'].nil?
|
83
|
+
@@credentials.aws_secret = credentials.params[profile]['aws_secret_access_key'] unless credentials.params[profile]['aws_secret_access_key'].nil?
|
78
84
|
end
|
79
|
-
errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_access_key_id')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@
|
80
|
-
errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_secret_access_key')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@
|
85
|
+
errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_access_key_id')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@credentials.aws_key.nil?
|
86
|
+
errors << "aws-cli error. Cannot find #{profile}: #{Blufin::Terminal::format_invalid('aws_secret_access_key')} in: #{Blufin::Terminal::format_directory(FILE_AWS_CREDENTIALS)}" if @@credentials.aws_secret.nil?
|
81
87
|
else
|
82
88
|
errors << "aws-cli error. Cannot find file: #{Blufin::Terminal::format_invalid(FILE_AWS_CREDENTIALS)}"
|
83
89
|
end
|
@@ -109,7 +115,42 @@ module App
|
|
109
115
|
# If credentials don't exist (or are missing information) -- nil is returned.
|
110
116
|
# @return App::AWSCredentials
|
111
117
|
def self.get_credentials
|
112
|
-
@@
|
118
|
+
@@credentials
|
119
|
+
end
|
120
|
+
|
121
|
+
# Gets configured SSH users. Must be configured in YML and S3.
|
122
|
+
# @return Hash
|
123
|
+
def self.get_ssh_users
|
124
|
+
@@ssh_users.each do |user, pub_key|
|
125
|
+
Blufin::Terminal::error("Public key not found for user: #{Blufin::Terminal::format_invalid(user)}", "Expected file to exist: #{Blufin::Terminal::format_directory("#{user}.pub", false)}", true) if pub_key.nil?
|
126
|
+
end
|
127
|
+
@@ssh_users
|
128
|
+
end
|
129
|
+
|
130
|
+
# Gets Users from S3.
|
131
|
+
# Can be called multiple times (which you might do if you want to invalidate the cache).
|
132
|
+
# @return void
|
133
|
+
def self.download_s3_ssh_users(use_cache = true)
|
134
|
+
if @@profile.has_key?(SSH_KEYS)
|
135
|
+
s3 = @@profile[SSH_KEYS]['S3Bucket']
|
136
|
+
tmp_path = Blufin::AWS::download_s3_data(s3['Name'], s3['Path'], profile: @@profile[PROFILE], region: s3['Region'], use_cache: use_cache)
|
137
|
+
users = []
|
138
|
+
# Gets a unique list of users (since every user has 2 files, private and public key).
|
139
|
+
if Blufin::Files::path_exists(tmp_path)
|
140
|
+
Blufin::Files::get_files_in_dir(tmp_path).each do |file|
|
141
|
+
users << Blufin::Files::extract_file_name(file, false).gsub(/\.pub$/i, '')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
@@ssh_users = {} unless use_cache
|
145
|
+
users.uniq!
|
146
|
+
users.sort!
|
147
|
+
users.each do |user|
|
148
|
+
pub_key = "#{tmp_path}/#{user}.pub"
|
149
|
+
@@ssh_users[user] = Blufin::Files::file_exists(pub_key) ? pub_key : nil
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
113
154
|
end
|
114
155
|
|
115
156
|
end
|
data/lib/aws/aws_reports.rb
CHANGED
@@ -178,7 +178,7 @@ module App
|
|
178
178
|
|
179
179
|
# Returns a Hash with all the resources that can be auto-fetched using a script.
|
180
180
|
# @return Hash
|
181
|
-
def self.
|
181
|
+
def self.get_lookups(data)
|
182
182
|
auto_fetch_resources = {}
|
183
183
|
data.each do |resource|
|
184
184
|
if resource[1].has_key?(App::AWSReports::KEY_EXPORT)
|
data/lib/awx.rb
CHANGED
@@ -52,11 +52,13 @@ TEMPLATE
|
|
52
52
|
awx_cloudformation.command :create, :aliases => [:c] do |awx_cloudformation_create|
|
53
53
|
awx_cloudformation_create.summary 'Create stack'
|
54
54
|
awx_cloudformation_create.options do |opts|
|
55
|
+
opts.opt :clear_cache, 'Clear cache', :short => '-c', :long => '--clear-cache', :type => :boolean
|
56
|
+
opts.opt :rerun, "Re-run previous with cached values (if exists) \xe2\x80\x94 #{Blufin::Terminal::format_invalid('@NotImplemented')}", :short => '-r', :long => '--re-run', :type => :boolean
|
57
|
+
|
55
58
|
# TODO AWX PROFILE - Must support S3.
|
56
59
|
if Blufin::Files::path_exists("#{File.expand_path(App::AWSProfile::get_profile['CloudFormation']['Templates']['Local']['Path'])}/test")
|
57
60
|
opts.opt :test, 'Run through test-template.', :short => '-t', :long => '--test', :type => :boolean
|
58
61
|
end
|
59
|
-
opts.opt :test, "Re-run previous with cached values (if exists) \xe2\x80\x94 #{Blufin::Terminal::format_invalid('@NotImplemented')}", :short => '-R', :long => '--re-run', :type => :boolean
|
60
62
|
end
|
61
63
|
awx_cloudformation_create.action do |opts, args|
|
62
64
|
AppCommand::AWSCloudFormationCreate.new(opts, args).execute
|
@@ -29,8 +29,8 @@ module AppCommand
|
|
29
29
|
SPACER = '<<--Spacer-->>'
|
30
30
|
CAPABILITIES = 'Capabilities'
|
31
31
|
RETURN_VALUE = 'PjNkHK33EopWxCpzOQfuku3la'
|
32
|
-
|
33
|
-
|
32
|
+
SSH_USERS = 'SSHUsers'
|
33
|
+
SYSTEM = 'System'
|
34
34
|
|
35
35
|
def execute
|
36
36
|
|
@@ -39,21 +39,22 @@ module AppCommand
|
|
39
39
|
@opts = command_options
|
40
40
|
@args = arguments
|
41
41
|
|
42
|
-
@template
|
43
|
-
@templates
|
44
|
-
@params
|
45
|
-
@
|
46
|
-
@
|
47
|
-
@
|
48
|
-
@
|
49
|
-
@
|
50
|
-
@
|
51
|
-
@
|
52
|
-
@
|
53
|
-
@
|
54
|
-
@
|
55
|
-
@
|
56
|
-
@
|
42
|
+
@template = nil
|
43
|
+
@templates = {}
|
44
|
+
@params = {}
|
45
|
+
@params_system = nil
|
46
|
+
@output = {}
|
47
|
+
@regions = App::AWSCli::get_regions
|
48
|
+
@lookups = {}
|
49
|
+
@lookup_cache = {}
|
50
|
+
@data = nil
|
51
|
+
@table_widths = {}
|
52
|
+
@export_map = {}
|
53
|
+
@columns = {}
|
54
|
+
@options_default = {}
|
55
|
+
@cache = {}
|
56
|
+
@cache_valid = false
|
57
|
+
@projects = {}
|
57
58
|
|
58
59
|
@terminal_width = Blufin::Terminal::get_terminal_width
|
59
60
|
@columns, @data, @export_map, @table_widths = App::AWSReports::parse_metadata(@regions)
|
@@ -76,18 +77,28 @@ module AppCommand
|
|
76
77
|
# Windows is currently not supported, so bomb-out.
|
77
78
|
Blufin::Tools::os_not_supported([Blufin::Tools::OS_WINDOWS])
|
78
79
|
|
80
|
+
# If clear-cache flag is set, removed all cached stuff.
|
81
|
+
if @opts[:clear_cache]
|
82
|
+
# Clear out the SSH keys (cached from S3).
|
83
|
+
App::AWSProfile::download_s3_ssh_users(false)
|
84
|
+
end
|
85
|
+
|
79
86
|
# If Terminal window is smaller than 230, bomb-out.
|
80
87
|
terminal_width_actual = Blufin::Terminal::get_terminal_width
|
81
88
|
terminal_required_width = 227
|
82
89
|
Blufin::Terminal::error("Output for this command \x1B[38;5;240m(#{Blufin::Terminal::format_action(terminal_required_width)}\x1B[38;5;240m-width)\x1B[0m does not fit in Terminal \x1B[38;5;240m(#{Blufin::Terminal::format_action(terminal_width_actual)}\x1B[38;5;240m-width)\x1B[0m", 'Please make your terminal wider and try again.', true) if terminal_width_actual < terminal_required_width
|
83
90
|
|
84
|
-
@warnings
|
85
|
-
@
|
91
|
+
@warnings = []
|
92
|
+
@lookups = App::AWSReports::get_lookups(@data)
|
93
|
+
|
94
|
+
# Add SSH Users to Lookups (if they've been configured).
|
95
|
+
users = App::AWSProfile::get_ssh_users
|
96
|
+
@lookups[SSH_USERS] = users if users.any?
|
86
97
|
|
87
98
|
@options_default[OPTION_ENVIRONMENT] = Blufin::Projects::get_environments
|
88
|
-
@options_default[OPTION_REGION] = App::AWSProfile::get_profile[
|
89
|
-
@options_default[OPTION_STACK_NAME] = App::AWSProfile::get_profile[
|
90
|
-
@options_default[OPTION_TIMEOUT] = App::AWSProfile::get_profile[
|
99
|
+
@options_default[OPTION_REGION] = App::AWSProfile::get_profile[App::AWSProfile::CLOUDFORMATION]['Defaults']['Regions']
|
100
|
+
@options_default[OPTION_STACK_NAME] = App::AWSProfile::get_profile[App::AWSProfile::CLOUDFORMATION]['Defaults']['StackName']
|
101
|
+
@options_default[OPTION_TIMEOUT] = App::AWSProfile::get_profile[App::AWSProfile::CLOUDFORMATION]['Defaults']['Timeout']
|
91
102
|
@options_default[OPTION_PROJECT] = Blufin::Projects::get_project_names
|
92
103
|
|
93
104
|
# Loop the entire blufin-secrets/cloudformation path(s) and validate all the template(s).
|
@@ -147,11 +158,12 @@ module AppCommand
|
|
147
158
|
'MaxLength' => false,
|
148
159
|
'MaxValue' => false,
|
149
160
|
'ConstraintDescription' => false,
|
161
|
+
'NoEcho' => false,
|
150
162
|
}
|
151
163
|
Blufin::Validate::assert_valid_keys(expected, param_data.keys, "#{file} \xe2\x86\x92 #{param_name}")
|
152
164
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Template has reserved parameter: #{Blufin::Terminal::format_invalid(param_name)}" if [OPTION_STACK_NAME.downcase].concat(RESERVED_WORDS).include?(param_name.downcase)
|
153
165
|
parameters[param_name] = param_data
|
154
|
-
if @
|
166
|
+
if @lookups.has_key?(param_name)
|
155
167
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Parameter: #{param_name} cannot have default value: '#{param_data[DEFAULT]}' because it is a live look-up list (from AWS)." if param_data.keys.include?(DEFAULT)
|
156
168
|
end
|
157
169
|
# Validate parameter type.
|
@@ -207,24 +219,11 @@ module AppCommand
|
|
207
219
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 AllowedValues must be Array, instead got: #{Blufin::Terminal::format_invalid(param_data['AllowedValues'].class)}"
|
208
220
|
end
|
209
221
|
end
|
210
|
-
# Validate EC2UserData parameter (make sure cloud-init.txt exists).
|
211
|
-
if param_name == EC2_USER_DATA
|
212
|
-
cloud_init_file = "#{template_path}/#{EC2_USER_DATA_FILE}"
|
213
|
-
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Template has #{Blufin::Terminal::format_highlight(EC2_USER_DATA)} parameter but no #{Blufin::Terminal::format_invalid(EC2_USER_DATA_FILE)} file." unless Blufin::Files::file_exists(cloud_init_file)
|
214
|
-
end
|
215
222
|
end
|
216
223
|
end
|
217
224
|
# Validate description (if exists).
|
218
225
|
if yml_data.has_key?(OPTION_DESCRIPTION)
|
219
226
|
description = yml_data[OPTION_DESCRIPTION]
|
220
|
-
# Validate replaceable value(s) exist.
|
221
|
-
matches = description.scan(/{{[A-Za-z0-9]+}}/)
|
222
|
-
matches.each do |match|
|
223
|
-
match = match.gsub(/^{{/, '').gsub(/}}$/, '')
|
224
|
-
unless parameters.keys.include?(match)
|
225
|
-
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid description matcher: #{Blufin::Terminal::format_invalid(match)}"
|
226
|
-
end
|
227
|
-
end
|
228
227
|
else
|
229
228
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Template is missing description."
|
230
229
|
end
|
@@ -267,24 +266,9 @@ module AppCommand
|
|
267
266
|
# Validate stack name.
|
268
267
|
if stack_name.nil? || stack_name.strip == ''
|
269
268
|
stack_name = @options_default[OPTION_STACK_NAME]
|
270
|
-
else
|
271
|
-
# Validate Stack Name (if exists).
|
272
|
-
matches = stack_name.scan(/{{[A-Za-z0-9]+}}/)
|
273
|
-
matches.each do |match|
|
274
|
-
match = match.gsub(/^{{/, '').gsub(/}}$/, '')
|
275
|
-
if match != match.upcase
|
276
|
-
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 All stack-name matchers must be uppercase, found: #{Blufin::Terminal::format_invalid(match)}"
|
277
|
-
next
|
278
|
-
end
|
279
|
-
unless MATCHERS.include?(match)
|
280
|
-
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid stack-name matcher: #{Blufin::Terminal::format_invalid(match)}"
|
281
|
-
end
|
282
|
-
stack_name_stripped = stack_name.gsub(/{{[A-Za-z0-9]+}}/, '')
|
283
|
-
if stack_name_stripped !~ /[a-z0-9\-]/
|
284
|
-
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Stack-name has invalid or non-matcher, uppercase characters: #{Blufin::Terminal::format_invalid(stack_name)} \x1B[38;5;240m(#{stack_name_stripped})\x1B[0m"
|
285
|
-
end
|
286
|
-
end
|
287
269
|
end
|
270
|
+
results = Blufin::Replacer::scan_string(stack_name)
|
271
|
+
validate_matchers(file_cloudformation, results, template_name, parameters)
|
288
272
|
# Make sure deployment stack is not a reserved word.
|
289
273
|
if deployment_stack.is_a?(String) && %w(lambda).include?(deployment_stack.downcase)
|
290
274
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 #{Blufin::Terminal::format_highlight('DEPLOYMENT_STACK')} value is a reserved word: #{Blufin::Terminal::format_invalid(deployment_stack)}"
|
@@ -334,7 +318,7 @@ module AppCommand
|
|
334
318
|
Object.send(:remove_const, :Template)
|
335
319
|
end
|
336
320
|
end
|
337
|
-
#
|
321
|
+
# Validate no-sort parameters (if exist).
|
338
322
|
unless parameters_no_sort.nil?
|
339
323
|
if parameters_no_sort.is_a?(Array)
|
340
324
|
parameters_no_sort.each do |pns|
|
@@ -344,6 +328,12 @@ module AppCommand
|
|
344
328
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Expected constant #{Blufin::Terminal::format_highlight('PARAMETERS_NO_SORT')} to be Array, instead got: #{Blufin::Terminal::format_invalid(parameters_no_sort.class)}"
|
345
329
|
end
|
346
330
|
end
|
331
|
+
# Validate template matchers.
|
332
|
+
unless file_cloudformation.nil?
|
333
|
+
results = Blufin::Replacer::scan_file(file_cloudformation)
|
334
|
+
# Handle errors first.
|
335
|
+
validate_matchers(file_cloudformation, results, template_name, parameters)
|
336
|
+
end
|
347
337
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 The #{Blufin::Terminal::format_highlight('template.yml')}\x1B[38;5;240m is missing, empty or invalid." if file_cloudformation.nil?
|
348
338
|
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 The #{Blufin::Terminal::format_highlight('template.rb')}\x1B[38;5;240m is missing, empty or invalid." if file_ruby.nil?
|
349
339
|
@templates[category] = {} unless @templates.has_key?(category)
|
@@ -391,8 +381,8 @@ module AppCommand
|
|
391
381
|
|
392
382
|
def opts_routing
|
393
383
|
|
394
|
-
used_cache
|
395
|
-
showing_tags
|
384
|
+
used_cache = true
|
385
|
+
showing_tags = false
|
396
386
|
|
397
387
|
# Show prompt to select template.
|
398
388
|
category, template, @template = select_template_prompt
|
@@ -455,11 +445,19 @@ module AppCommand
|
|
455
445
|
capabilities_arr = []
|
456
446
|
capabilities_str = nil
|
457
447
|
|
448
|
+
# Replace matchers in CloudFormation Template before uploading to S3.
|
449
|
+
source = File.expand_path("#{App::AWSCloudFormation::get_cloudformation_path}/#{category}/#{template}/template.yml")
|
450
|
+
raise RuntimeError, "File does not exist: #{source}" unless Blufin::Files::file_exists(source)
|
451
|
+
file_lines = Blufin::Replacer::replace_yml(source, get_replacer_params(category, template))
|
452
|
+
tmp_file = "/tmp/converted-template-#{Blufin::Strings::random_string(4)}.txt"
|
453
|
+
Blufin::Files::write_file(tmp_file, file_lines)
|
454
|
+
|
458
455
|
# Upload the template to S3.
|
459
|
-
s3_url
|
456
|
+
s3_url = App::AWSCloudFormation::upload_cloudformation_template(tmp_file, category, template)
|
457
|
+
system("rm #{tmp_file}")
|
460
458
|
|
461
459
|
# Validates the template.
|
462
|
-
validation
|
460
|
+
validation = App::AWSCli::cloudformation_stack_validate(@params[OPTION_REGION], s3_url)
|
463
461
|
|
464
462
|
# Check if validation output is JSON (and output appropriate format).
|
465
463
|
begin
|
@@ -604,8 +602,9 @@ module AppCommand
|
|
604
602
|
raise RuntimeError, "Template with category: #{category} and Id: #{template} does not exist." unless @templates.has_key?(category) && @templates[category].has_key?(template)
|
605
603
|
Blufin::Terminal::error("Template: #{Blufin::Terminal::format_highlight(@templates[category][template][:name])} is currently broken/incomplete.", 'Please fix error(s) and try again.', true) if @templates[category][template][:broken]
|
606
604
|
end
|
607
|
-
@params
|
608
|
-
@
|
605
|
+
@params = {}
|
606
|
+
@params_system = nil
|
607
|
+
@template = @templates[category][template].dup
|
609
608
|
system('clear')
|
610
609
|
@template[:parameters] = {} if !@template.has_key?(:parameters) || !@template[:parameters].any?
|
611
610
|
# Show summary (with intro if exists).
|
@@ -671,14 +670,12 @@ module AppCommand
|
|
671
670
|
OPTION_DESCRIPTION => 'Should this stack be protected against accidental Termination?'
|
672
671
|
}
|
673
672
|
end
|
674
|
-
# If one of the parameters is EC2UserData, this parameter gets handled differently.
|
675
|
-
if @template[:parameters].is_a?(Hash) && @template[:parameters].has_key?(EC2_USER_DATA)
|
676
|
-
@template[:parameters][EC2_USER_DATA][OPTION_DESCRIPTION] = "#{EC2_USER_DATA_FILE} (base64 encoded & sent automatically)"
|
677
|
-
end
|
678
673
|
# Get cached values (if exist and parameters haven't changed).
|
679
674
|
# Even a one-character change in a description will invalidate the cache.
|
680
675
|
cache_file = get_cache_file(category, template)
|
681
|
-
|
676
|
+
# Remove cache file (if --clear-cache flag is set).
|
677
|
+
Blufin::Terminal::execute("rm #{cache_file}", verbose: false) if @opts[:clear_cache] && Blufin::Files::file_exists(cache_file)
|
678
|
+
@cache = {}
|
682
679
|
if Blufin::Files::file_exists(cache_file)
|
683
680
|
@cache = nil
|
684
681
|
@cache_valid = false
|
@@ -697,13 +694,13 @@ module AppCommand
|
|
697
694
|
table_data = []
|
698
695
|
# Loop again to build output.
|
699
696
|
@template[:parameters].each do |param_name, param_data|
|
700
|
-
if @
|
697
|
+
if @lookups.has_key?(param_name)
|
701
698
|
params_to_fetch << param_name
|
702
699
|
params_to_fetch_colored << "\x1B[38;5;61m#{param_name}\x1B[38;5;208m"
|
703
700
|
end
|
704
701
|
ti = (param_data.has_key?(OPTIONS) ? :system : :normal)
|
705
702
|
table_data << {
|
706
|
-
:type_internal => @
|
703
|
+
:type_internal => @lookups.has_key?(param_name) ? :autocomplete : ti,
|
707
704
|
:parameter => param_name,
|
708
705
|
:type => %w(string number boolean).include?(param_data['Type'].downcase) ? param_data['Type'] : SPECIAL,
|
709
706
|
:description => param_data.has_key?('Description') ? param_data['Description'] : "\xe2\x80\x94",
|
@@ -728,7 +725,7 @@ module AppCommand
|
|
728
725
|
params_to_fetch.each do |ptf|
|
729
726
|
sleep(0.01)
|
730
727
|
threads << Thread.new {
|
731
|
-
options = fetch_autocomplete_options(ptf, silent: true)
|
728
|
+
options, multi = fetch_autocomplete_options(ptf, silent: true)
|
732
729
|
if options.nil? || !options.any?
|
733
730
|
empty_options << "\x1B[38;5;196m#{ptf}\x1B[0m \xe2\x80\x94 \x1B[38;5;240mFound 0 result(s)."
|
734
731
|
end
|
@@ -742,15 +739,13 @@ module AppCommand
|
|
742
739
|
end
|
743
740
|
# If we have any auto-complete options that come back empty, we show an error and disable certain options.
|
744
741
|
if empty_options.any?
|
745
|
-
Blufin::Terminal::error("Cannot currently use this template because
|
746
|
-
puts
|
747
|
-
choices = []
|
742
|
+
Blufin::Terminal::error("Cannot currently use this template because empty #{Blufin::Terminal::format_highlight('required resource(s)')} were detected.", empty_options, true, false)
|
748
743
|
else
|
749
|
-
choices = [{value: 'y', text: 'Select this template'}]
|
750
|
-
choices << {value: 'Y', text: "Select this template \x1B[38;5;198m(and apply cached values)\x1B[0m"} if @cache_valid
|
744
|
+
choices = [{ value: 'y', text: 'Select this template' }]
|
745
|
+
choices << { value: 'Y', text: "Select this template \x1B[38;5;198m(and apply cached values)\x1B[0m" } if @cache_valid
|
751
746
|
end
|
752
747
|
# The prompt at the end of the intro.
|
753
|
-
choices << {value: 'n', text: "\x1B[38;5;240m#{Blufin::Strings::RETURN_CHARACTER}\x1B[0m"}
|
748
|
+
choices << { value: 'n', text: "\x1B[38;5;240m#{Blufin::Strings::RETURN_CHARACTER}\x1B[0m" }
|
754
749
|
choice = Blufin::Terminal::prompt_select('What would you like to do?', choices)
|
755
750
|
case choice
|
756
751
|
when 'y'
|
@@ -772,17 +767,13 @@ module AppCommand
|
|
772
767
|
def get_parameter_value(param_data, param_name, category, template)
|
773
768
|
description = param_data.has_key?(OPTION_DESCRIPTION) ? param_data[OPTION_DESCRIPTION] : nil
|
774
769
|
options_text = "Select #{param_name}:"
|
770
|
+
replace_hash = get_replacer_params(category, template)
|
775
771
|
if [OPTION_STACK_NAME].include?(param_name)
|
776
772
|
constraints = []
|
777
773
|
constraints << "\x1B[38;5;240mMinLength: \x1B[38;5;#{App::AWSOutputter::CONSTRAINT_COLOR}m#{param_data['MinLength']}" if param_data.has_key?('MinLength')
|
778
774
|
constraints << "\x1B[38;5;240mMaxLength: \x1B[38;5;#{App::AWSOutputter::CONSTRAINT_COLOR}m#{param_data['MaxLength']}" if param_data.has_key?('MaxLength')
|
779
775
|
default = @template[:stack_name]
|
780
|
-
default = default
|
781
|
-
default = default.gsub(/{{TEMPLATE}}/i, template) if default =~ /{{TEMPLATE}}/i
|
782
|
-
default = default.gsub(/{{PROJECT}}/i, @params[OPTION_PROJECT]) if default =~ /{{PROJECT}}/i
|
783
|
-
default = default.gsub(/{{ENVIRONMENT}}/i, @params[OPTION_ENVIRONMENT]) if default =~ /{{ENVIRONMENT}}/i
|
784
|
-
default = default.gsub(/{{REGION}}/i, @params[OPTION_REGION]) if default =~ /{{REGION}}/i
|
785
|
-
default = default.gsub(/{{UUID}}/i, random_stack_suffix) if default =~ /{{UUID}}/i
|
776
|
+
default = Blufin::Replacer::replace_string(default, replace_hash)
|
786
777
|
default = default.downcase
|
787
778
|
help_text = 'Stack Name (will be displayed in CloudFormation console).'
|
788
779
|
return Blufin::Terminal::prompt_ask("Enter #{param_name}#{render_constraints(constraints)}", default: default, help: help_text)
|
@@ -790,28 +781,33 @@ module AppCommand
|
|
790
781
|
constraints = []
|
791
782
|
constraints << "\x1B[38;5;240mMinLength: \x1B[38;5;#{App::AWSOutputter::CONSTRAINT_COLOR}m#{param_data['MinLength']}" if param_data.has_key?('MinLength')
|
792
783
|
constraints << "\x1B[38;5;240mMaxLength: \x1B[38;5;#{App::AWSOutputter::CONSTRAINT_COLOR}m#{param_data['MaxLength']}" if param_data.has_key?('MaxLength')
|
793
|
-
default
|
794
|
-
|
795
|
-
# Check if description has any replaceable values.
|
796
|
-
default = replace_matchers_with_params(default, @params)
|
797
|
-
end
|
784
|
+
default = param_data.has_key?(DEFAULT) ? param_data[DEFAULT] : nil
|
785
|
+
default = Blufin::Replacer::replace_string(default, replace_hash)
|
798
786
|
help_text = 'Description (will be displayed in CloudFormation console).'
|
799
787
|
return Blufin::Terminal::prompt_ask("Enter #{param_name}#{render_constraints(constraints)}", default: default, help: help_text)
|
800
|
-
elsif param_name == EC2_USER_DATA
|
801
|
-
puts Blufin::Terminal::display_prompt_text(EC2_USER_DATA, EC2_USER_DATA_FILE)
|
802
|
-
return "#{@template[:path]}/#{EC2_USER_DATA_FILE}"
|
803
788
|
elsif param_name == OPTION_TIMEOUT
|
804
789
|
return param_data[DEFAULT]
|
805
790
|
elsif param_name == OPTION_TERM_PROTECT
|
806
791
|
# Basically, by default Termination Protection is off (because most of the time your just testing and want to press Enter).
|
807
792
|
return !Blufin::Terminal::prompt_yes?("Allow accidental Termination? (type 'n' to enable Termination Protection)")
|
808
|
-
elsif @
|
793
|
+
elsif @lookups.has_key?(param_name)
|
809
794
|
# Sort alphabetically.
|
810
|
-
options = fetch_autocomplete_options(param_name, silent: true)
|
795
|
+
options, multi = fetch_autocomplete_options(param_name, silent: true)
|
811
796
|
options.sort_by! { |hsh| hsh[:sort] }
|
812
797
|
# If we have a cached value, make that the first in the options list.
|
813
798
|
options = move_default_option_to_top(options, param_name) if @cache.has_key?(param_name)
|
814
|
-
|
799
|
+
if multi && options.length > 1
|
800
|
+
selected_values = []
|
801
|
+
selected_values = Blufin::Terminal::prompt_multi_select(options_text, options, help: description) until selected_values.any?
|
802
|
+
return selected_values
|
803
|
+
else
|
804
|
+
if options.length == 1
|
805
|
+
puts Blufin::Terminal::display_prompt_text(options_text, options[0][:text])
|
806
|
+
return multi ? [options[0][:value]] : options[0][:value]
|
807
|
+
else
|
808
|
+
return Blufin::Terminal::prompt_select(options_text, options, help: description)
|
809
|
+
end
|
810
|
+
end
|
815
811
|
elsif param_data.has_key?(OPTIONS) || param_data.has_key?('AllowedValues')
|
816
812
|
options = param_data[OPTIONS]
|
817
813
|
options = param_data['AllowedValues'] if param_data.has_key?('AllowedValues')
|
@@ -829,7 +825,13 @@ module AppCommand
|
|
829
825
|
# If we have a cached value, make that the first in the options list.
|
830
826
|
options = move_default_option_to_top(options, param_name) if @cache.has_key?(param_name)
|
831
827
|
puts Blufin::Terminal::display_prompt_help(param_data[OPTION_DESCRIPTION]) if param_data.has_key?(OPTION_DESCRIPTION)
|
832
|
-
|
828
|
+
if param_data['Type'] == 'CommaDelimitedList'
|
829
|
+
selected_values = []
|
830
|
+
selected_values = Blufin::Terminal::prompt_multi_select(options_text, options) until selected_values.any?
|
831
|
+
return selected_values
|
832
|
+
else
|
833
|
+
return Blufin::Terminal::prompt_select(options_text, options)
|
834
|
+
end
|
833
835
|
end
|
834
836
|
else
|
835
837
|
constraints = []
|
@@ -842,10 +844,7 @@ module AppCommand
|
|
842
844
|
if default.nil?
|
843
845
|
default = @cache[param_name] if @cache.has_key?(param_name)
|
844
846
|
else
|
845
|
-
|
846
|
-
matches = default.scan(/{{(System):([A-Za-z0-9]+)}}/)
|
847
|
-
default = replace_with_dynamic_data(default, matches) if matches.any?
|
848
|
-
end
|
847
|
+
default = Blufin::Replacer::replace_string(default, replace_hash)
|
849
848
|
end
|
850
849
|
loop do
|
851
850
|
value = Blufin::Terminal::prompt_ask("Enter #{param_name}#{render_constraints(constraints)}", default: default, help: description)
|
@@ -868,35 +867,50 @@ module AppCommand
|
|
868
867
|
puts
|
869
868
|
end
|
870
869
|
|
871
|
-
#
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
matcher_pairs.each do |pair|
|
878
|
-
matcher = "#{pair[0]}:#{pair[1]}"
|
879
|
-
case matcher
|
880
|
-
when 'System:RandomString'
|
881
|
-
original_string = original_string.gsub('{{System:RandomString}}', Blufin::Strings::random_string)
|
882
|
-
else
|
883
|
-
raise RuntimeError, "Unrecognized matcher: #{Blufin::Terminal::format_invalid(matcher)}"
|
870
|
+
# Recursive function to validate matchers.
|
871
|
+
# @return void
|
872
|
+
def validate_matchers(file_cloudformation, results, template_name, parameters)
|
873
|
+
if results[:errors].any?
|
874
|
+
results[:errors].each do |error|
|
875
|
+
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid matcher found in template: #{Blufin::Terminal::format_invalid(error)}"
|
884
876
|
end
|
885
877
|
end
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
878
|
+
# Still validate matchers regardless (in case there are more errors).
|
879
|
+
if results[:matchers].any?
|
880
|
+
results[:matchers].each do |key, matchers|
|
881
|
+
raise RuntimeError, "Expected Array, but got #{matchers.class}" unless matchers.is_a?(Array)
|
882
|
+
matchers.each do |m|
|
883
|
+
matcher_raw = "${{#{key}:#{m[:key]}#{m.has_key?(:modifier) ? ":#{m[:modifier]}" : ''}}}"
|
884
|
+
begin
|
885
|
+
case key
|
886
|
+
when PARAMETERS
|
887
|
+
valid_keys = parameters.keys.push(*[
|
888
|
+
OPTION_CATEGORY,
|
889
|
+
OPTION_TEMPLATE,
|
890
|
+
OPTION_PROJECT,
|
891
|
+
OPTION_ENVIRONMENT,
|
892
|
+
OPTION_REGION
|
893
|
+
])
|
894
|
+
raise RuntimeError unless valid_keys.include?(m[:key])
|
895
|
+
when SYSTEM
|
896
|
+
raise RuntimeError unless %w(UUID-8 UUID-16 UUID-AWX).include?(m[:key])
|
897
|
+
when 'file'
|
898
|
+
file_path = "#{Blufin::Files::extract_path_name(file_cloudformation)}/#{m[:key]}"
|
899
|
+
unless Blufin::Files::file_exists(file_path)
|
900
|
+
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 File from matcher not found: #{Blufin::Terminal::format_invalid(file_path)}"
|
901
|
+
next
|
902
|
+
end
|
903
|
+
results_inner = Blufin::Replacer::scan_file(file_path)
|
904
|
+
validate_matchers(file_path, results_inner, template_name, parameters)
|
905
|
+
else
|
906
|
+
raise RuntimeError
|
907
|
+
end
|
908
|
+
rescue
|
909
|
+
@warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid matcher found in template: #{Blufin::Terminal::format_invalid(matcher_raw)}"
|
910
|
+
end
|
911
|
+
end
|
897
912
|
end
|
898
913
|
end
|
899
|
-
default
|
900
914
|
end
|
901
915
|
|
902
916
|
# Moves the default option to the top of the list.
|
@@ -918,14 +932,27 @@ module AppCommand
|
|
918
932
|
# Goes off to AWS and gets values for autocomplete supported fields.
|
919
933
|
# @return string
|
920
934
|
def fetch_autocomplete_options(resource_name, silent: true)
|
921
|
-
raise RuntimeError, "Key not found in @
|
922
|
-
return @
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
935
|
+
raise RuntimeError, "Key not found in @lookups: #{resource_name}" unless @lookups.has_key?(resource_name)
|
936
|
+
return @lookup_cache[resource_name] if @lookup_cache.has_key?(resource_name)
|
937
|
+
multi = false
|
938
|
+
if resource_name == SSH_USERS
|
939
|
+
multi = true
|
940
|
+
options = []
|
941
|
+
@lookups[SSH_USERS].each do |user, pub_key|
|
942
|
+
options << {
|
943
|
+
:value => pub_key,
|
944
|
+
:text => user,
|
945
|
+
:sort => user
|
946
|
+
}
|
947
|
+
end
|
948
|
+
else
|
949
|
+
resource_title = @lookups[resource_name][:resource_title]
|
950
|
+
resource = @lookups[resource_name][:resource]
|
951
|
+
results = App::AWSReports::get_aws_data(@regions, resource, resource_title, silent: silent)
|
952
|
+
options = App::AWSReports::parse_results_for_prompt(resource, resource_name, results)
|
953
|
+
end
|
954
|
+
@lookup_cache[resource_name] = options, multi
|
955
|
+
return options, multi
|
929
956
|
end
|
930
957
|
|
931
958
|
# Returns short-hand syntax for tags.
|
@@ -957,17 +984,17 @@ module AppCommand
|
|
957
984
|
def assemble_params(params)
|
958
985
|
output = []
|
959
986
|
params.each do |key, value|
|
960
|
-
if key == EC2_USER_DATA
|
961
|
-
b64_cmd = Blufin::Tools::value_based_on_os(mac: "openssl base64 -in #{value}", linux: "base64 -w0 #{value}")
|
962
|
-
result = Blufin::Terminal::command_capture(b64_cmd, nil, nil, nil)[0]
|
963
|
-
result = result.split("\n").join('')
|
964
|
-
output << {
|
965
|
-
'ParameterKey' => key,
|
966
|
-
'ParameterValue' => result
|
967
|
-
}
|
968
|
-
next
|
969
|
-
end
|
970
987
|
unless RESERVED_WORDS.include?(key.downcase)
|
988
|
+
# If this is a list, produce comma delimited output.
|
989
|
+
if @template[:parameters].has_key?(key)
|
990
|
+
if %w(List<Number> CommaDelimitedList).include?(@template[:parameters][key]['Type'])
|
991
|
+
value_comma_delimited = ''
|
992
|
+
value.each do |val|
|
993
|
+
value_comma_delimited = "#{value_comma_delimited},#{val.gsub(',', '\,')}"
|
994
|
+
end
|
995
|
+
value = value_comma_delimited[1..-1]
|
996
|
+
end
|
997
|
+
end
|
971
998
|
output << {
|
972
999
|
'ParameterKey' => key,
|
973
1000
|
'ParameterValue' => value
|
@@ -1016,10 +1043,35 @@ module AppCommand
|
|
1016
1043
|
constraints.any? ? " \x1B[38;5;#{constraint_bracket_color}m[ #{constraints.join("\x1B[38;5;240m | ")} \x1B[38;5;#{constraint_bracket_color}m] \x1B[38;5;214m:" : ':'
|
1017
1044
|
end
|
1018
1045
|
|
1046
|
+
# Returns system params (such as -> System:UUID-AWX for example)
|
1047
|
+
# @return Hash
|
1048
|
+
def get_system_params
|
1049
|
+
if @params_system.nil?
|
1050
|
+
@params_system = {
|
1051
|
+
'UUID-8' => Blufin::Strings::random_string(1),
|
1052
|
+
'UUID-16' => Blufin::Strings::random_string(2),
|
1053
|
+
'UUID-AWX' => random_stack_suffix,
|
1054
|
+
}
|
1055
|
+
end
|
1056
|
+
@params_system
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
# Returns replacer params, generated new for each call.
|
1060
|
+
# @return Hash
|
1061
|
+
def get_replacer_params(category, template)
|
1062
|
+
params = @params
|
1063
|
+
params[OPTION_CATEGORY] = category
|
1064
|
+
params[OPTION_TEMPLATE] = template
|
1065
|
+
{
|
1066
|
+
PARAMETERS => params,
|
1067
|
+
SYSTEM => get_system_params
|
1068
|
+
}
|
1069
|
+
end
|
1070
|
+
|
1019
1071
|
# Generates a random stack suffix that always has the same patters: a[a-z0-9]w[a-z0-9]x
|
1020
1072
|
# @return string
|
1021
1073
|
def random_stack_suffix
|
1022
|
-
"a#{Blufin::Strings::random_string}10w17#{Blufin::Strings::random_string}x"
|
1074
|
+
"a#{Blufin::Strings::random_string(2)}10w17#{Blufin::Strings::random_string(2)}x"
|
1023
1075
|
end
|
1024
1076
|
|
1025
1077
|
# Replaces current random stack suffix with another one.
|
data/lib/routes/aws_list.rb
CHANGED
@@ -84,7 +84,7 @@ module AppCommand
|
|
84
84
|
|
85
85
|
# Display metadata and exit (if -m flag is set)
|
86
86
|
if @opts[:metadata]
|
87
|
-
App::AWSReports::
|
87
|
+
App::AWSReports::get_lookups(@data).each do |title, data|
|
88
88
|
output = []
|
89
89
|
output << "\x1B[38;5;240m AWS-CLI Command:\x1B[38;5;106m #{data[:resource][App::AWSReports::KEY_CLI]['command']}" if data[:resource].has_key?(App::AWSReports::KEY_CLI) && data[:resource][App::AWSReports::KEY_CLI].has_key?('command')
|
90
90
|
output << "\x1B[38;5;240m Region(s):\x1B[38;5;94m #{data[:resource][App::AWSReports::KEY_REGIONS].join(', ')}" if data[:resource].has_key?(App::AWSReports::KEY_REGIONS)
|
data/lib/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
AWX_VERSION = '0.5.
|
1
|
+
AWX_VERSION = '0.5.1'
|
data/opt/config/schema.yml
CHANGED
@@ -67,6 +67,18 @@ mapping:
|
|
67
67
|
Timeout:
|
68
68
|
type: int
|
69
69
|
required: yes
|
70
|
+
SSHKeys:
|
71
|
+
type: map
|
72
|
+
mapping:
|
73
|
+
S3Bucket:
|
74
|
+
type: map
|
75
|
+
mapping:
|
76
|
+
Name:
|
77
|
+
required: yes
|
78
|
+
Path:
|
79
|
+
required: yes
|
80
|
+
Region:
|
81
|
+
required: yes
|
70
82
|
Projects:
|
71
83
|
type: map
|
72
84
|
mapping:
|
data/opt/config/template.yml
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: awx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
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-08-
|
11
|
+
date: 2019-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: blufin-lib
|