awx 0.4.2 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8a94c9502e74dbf2341f840580ecef942de5f4b
4
- data.tar.gz: 1282d29984bc74544f9690e8165be5cc1d5e8937
3
+ metadata.gz: 54e617e3d455c0aa8d4f5d3dce0573cbb8ed86c3
4
+ data.tar.gz: 2039dffe2e3f9cc5e391fca408d726313280fcc7
5
5
  SHA512:
6
- metadata.gz: 80cb2a19a8ed00b096cfab3053ae90cfb32162f767f38cce76d86d985d364faaab670abf7629e7ae487aab3c7655cd557fc615f9179a330646a0eddb997b02c9
7
- data.tar.gz: fc84a4875cf90448c977a14f1e9849fb5685e1f0ef32b31d3a9676c04b37a479dc032ec24b9e0feb6c108b1237f09a60a3f7553f4fc9fb3549492123d1f2d591
6
+ metadata.gz: d050dcd91c40b5fb9fc39f38bba5854fe6790cc9cf77f262ab656bb0d8e666d63d0bafcd567a84a75c7142501e0e730bb559dfb5e48d73687d3528ebb02af699
7
+ data.tar.gz: 0cb3de40b28af605e5bbf33124a8c348c38441a95faa9a8fa90b81eafb8619fdf91d2ff6d8b74c0adadc71ae55739e6c50f70ba9d6ea35710f47406cecb3c1dc
@@ -5,7 +5,8 @@ module App
5
5
  # Gets the path to the root of the cloudformation templates in blufin-secrets repo.
6
6
  # @return string
7
7
  def self.get_cloudformation_path
8
- path = App::AWSProfile::get_profile['CloudFormation']['TemplatePath']
8
+ # TODO AWX PROFILE - Must support S3.
9
+ path = App::AWSProfile::get_profile['CloudFormation']['Templates']['Local']['Path']
9
10
  Blufin::Terminal::error("CloudFormation path not found: #{Blufin::Terminal::format_directory(path)}", 'This probably means directories got renamed or code got changed.', true) unless Blufin::Files::path_exists(path)
10
11
  path
11
12
  end
@@ -26,7 +27,7 @@ module App
26
27
  parsing_parameters = true
27
28
  Blufin::Files::read_file(tmp_file).each do |line|
28
29
  line = line.gsub("\n", '')
29
- if line.strip =~ /^description:/i
30
+ if line.strip =~ /^description:/i && !description_found
30
31
  new_lines << line unless description_found
31
32
  description_found = true
32
33
  else
@@ -44,7 +45,7 @@ module App
44
45
  template_filename = "#{template_category}-#{template_name}-#{DateTime.now.strftime('%Y%m%d-%H%M%S')}.yml"
45
46
  bucket_path = get_s3_bucket_path
46
47
  bucket_path = bucket_path == '' ? '' : "#{bucket_path}/"
47
- App::AWSCli::s3_upload(tmp_file, App::AWSProfile::get_profile['CloudFormation']['S3Bucket'], "#{bucket_path}#{template_filename}")
48
+ App::AWSCli::s3_upload(tmp_file, App::AWSProfile::get_profile['CloudFormation']['Uploads']['S3Bucket']['Name'], "#{bucket_path}#{template_filename}")
48
49
  # Return the S3 bucket URL.
49
50
  "#{get_s3_bucket_url}/#{template_filename}"
50
51
  end
@@ -54,13 +55,13 @@ module App
54
55
  def self.get_s3_bucket_url
55
56
  bucket_path = get_s3_bucket_path
56
57
  bucket_path = bucket_path == '' ? '' : "/#{bucket_path}"
57
- "https://#{App::AWSProfile::get_profile['CloudFormation']['S3Bucket']}.s3-#{App::AWSProfile::get_profile['CloudFormation']['S3BucketRegion']}.amazonaws.com#{bucket_path}"
58
+ "https://#{App::AWSProfile::get_profile['CloudFormation']['Uploads']['S3Bucket']['Name']}.s3-#{App::AWSProfile::get_profile['CloudFormation']['Uploads']['S3Bucket']['Region']}.amazonaws.com#{bucket_path}"
58
59
  end
59
60
 
60
61
  # Returns the S3 bucket path based on config parameters.
61
62
  # @return string
62
63
  def self.get_s3_bucket_path
63
- bucket_path = App::AWSProfile::get_profile['CloudFormation']['S3BucketPath']
64
+ bucket_path = App::AWSProfile::get_profile['CloudFormation']['Uploads']['S3Bucket']['Path']
64
65
  bucket_path.nil? || bucket_path.to_s.strip == '' ? '' : bucket_path
65
66
  end
66
67
 
@@ -48,8 +48,9 @@ module App
48
48
 
49
49
  # Validate CloudFormation data (if exists)
50
50
  if @@profile.has_key?(CLOUDFORMATION)
51
- cloudformation_template_path = @@profile[CLOUDFORMATION]['TemplatePath']
52
- s3_region = @@profile[CLOUDFORMATION]['S3BucketRegion']
51
+ # TODO AWX PROFILE - Must support S3.
52
+ cloudformation_template_path = @@profile[CLOUDFORMATION]['Templates']['Local']['Path']
53
+ s3_region = @@profile[CLOUDFORMATION]['Uploads']['S3Bucket']['Region']
53
54
  default_regions = @@profile[CLOUDFORMATION]['Defaults']['Regions']
54
55
  errors << "Path not found: #{Blufin::Terminal::format_invalid(cloudformation_template_path)}" unless Blufin::Files::path_exists(cloudformation_template_path)
55
56
  errors << "Invalid region: #{Blufin::Terminal::format_invalid(s3_region)}" unless App::AWS::VALID_REGIONS.include?(s3_region)
data/lib/awx.rb CHANGED
@@ -1,7 +1,7 @@
1
+ require 'blufin-lib'
1
2
  require 'columnist'
2
3
  require 'convoy'
3
4
  require 'yaml'
4
- require 'blufin-lib'
5
5
 
6
6
  require_relative 'version'
7
7
  require 'core/opt'
@@ -52,7 +52,8 @@ 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
- if Blufin::Files::path_exists("#{File.expand_path(App::AWSProfile::get_profile['CloudFormation']['TemplatePath'])}/test")
55
+ # TODO AWX PROFILE - Must support S3.
56
+ if Blufin::Files::path_exists("#{File.expand_path(App::AWSProfile::get_profile['CloudFormation']['Templates']['Local']['Path'])}/test")
56
57
  opts.opt :test, 'Run through test-template.', :short => '-t', :long => '--test', :type => :boolean
57
58
  end
58
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
@@ -29,6 +29,8 @@ module AppCommand
29
29
  SPACER = '<<--Spacer-->>'
30
30
  CAPABILITIES = 'Capabilities'
31
31
  RETURN_VALUE = 'PjNkHK33EopWxCpzOQfuku3la'
32
+ EC2_USER_DATA = 'EC2UserData'
33
+ EC2_USER_DATA_FILE = 'cloud-config.yml'
32
34
 
33
35
  def execute
34
36
 
@@ -71,6 +73,9 @@ module AppCommand
71
73
 
72
74
  def opts_validate
73
75
 
76
+ # Windows is currently not supported, so bomb-out.
77
+ Blufin::Tools::os_not_supported([Blufin::Tools::OS_WINDOWS])
78
+
74
79
  # If Terminal window is smaller than 230, bomb-out.
75
80
  terminal_width_actual = Blufin::Terminal::get_terminal_width
76
81
  terminal_required_width = 227
@@ -94,6 +99,7 @@ module AppCommand
94
99
  ps = path_inner.split('/')
95
100
  template = ps[ps.length - 1]
96
101
  template_name = "#{category}/#{template}"
102
+ template_path = nil
97
103
  file_cloudformation = nil
98
104
  file_ruby = nil
99
105
  method_before_create = nil
@@ -110,10 +116,12 @@ module AppCommand
110
116
  single_serve = false
111
117
  deployment_stack = nil
112
118
  parameters = {}
119
+ parameters_no_sort = nil
113
120
  warnings_count = @warnings.length
114
121
  raise RuntimeError, "Template name must consist of [service]/[service-description] with exactly one slash, instead got: #{template_name}" if template_name.strip.split('/').length != 2
115
122
  Blufin::Files::get_files_in_dir(path_inner).each do |file|
116
- filename = Blufin::Files::extract_file_name(file)
123
+ filename = Blufin::Files::extract_file_name(file)
124
+ template_path = Blufin::Files::extract_path_name(file)
117
125
  if filename == 'template.yml'
118
126
  begin
119
127
  yml_data = YAML.load_file(File.expand_path(file))
@@ -126,7 +134,7 @@ module AppCommand
126
134
  @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 AWSTemplateFormatVersion: '2010-09-09' is missing." unless yml_data.has_key?('AWSTemplateFormatVersion')
127
135
  @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 This template either has no resources, invalid resources, or something else wrong with the resources." if !yml_data.has_key?('Resources') || yml_data['Resources'].nil? || !yml_data['Resources'].is_a?(Hash) || yml_data['Resources'].length == 0
128
136
  if yml_data.has_key?(PARAMETERS) && yml_data[PARAMETERS].is_a?(Hash) && yml_data[PARAMETERS].length > 0
129
- yml_data[PARAMETERS].each do |resource_name, data|
137
+ yml_data[PARAMETERS].each do |param_name, param_data|
130
138
  # Validate keys are in specific order.
131
139
  expected = {
132
140
  'Type' => true,
@@ -140,72 +148,77 @@ module AppCommand
140
148
  'MaxValue' => false,
141
149
  'ConstraintDescription' => false,
142
150
  }
143
- Blufin::Validate::assert_valid_keys(expected, data.keys, "#{file} \xe2\x86\x92 #{resource_name}")
144
- @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Template has reserved parameter: #{Blufin::Terminal::format_invalid(resource_name)}" if [OPTION_STACK_NAME.downcase].concat(RESERVED_WORDS).include?(resource_name.downcase)
145
- parameters[resource_name] = data
146
- if @auto_fetch_resources.has_key?(resource_name)
147
- @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Parameter: #{resource_name} cannot have default value: '#{data[DEFAULT]}' because it is a live look-up list (from AWS)." if data.keys.include?(DEFAULT)
151
+ Blufin::Validate::assert_valid_keys(expected, param_data.keys, "#{file} \xe2\x86\x92 #{param_name}")
152
+ @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
+ parameters[param_name] = param_data
154
+ if @auto_fetch_resources.has_key?(param_name)
155
+ @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)
148
156
  end
149
157
  # Validate parameter type.
150
158
  valid_parameter_types = %w(String Number List<Number> CommaDelimitedList)
151
159
  valid_parameter_regexes = [/^AWS::[A-Za-z0-9]+::[A-Za-z0-9]+::[A-Za-z0-9]+$/, /^List<AWS::[A-Za-z0-9]+::[A-Za-z0-9]+::[A-Za-z0-9]+>$/]
152
- unless valid_parameter_types.include?(data['Type'])
160
+ unless valid_parameter_types.include?(param_data['Type'])
153
161
  matches_vpr = false
154
162
  valid_parameter_regexes.each do |vpr|
155
- matches_vpr = true if data['Type'] =~ vpr
163
+ matches_vpr = true if param_data['Type'] =~ vpr
156
164
  end
157
165
  if matches_vpr
158
166
  constraints = []
159
- constraints << 'AllowedPattern' if data.has_key?('AllowedPattern')
160
- constraints << 'MinLength' if data.has_key?('MinLength')
161
- constraints << 'MaxLength' if data.has_key?('MaxLength')
162
- constraints << 'MinValue' if data.has_key?('MinValue')
163
- constraints << 'MaxValue' if data.has_key?('MaxValue')
167
+ constraints << 'AllowedPattern' if param_data.has_key?('AllowedPattern')
168
+ constraints << 'MinLength' if param_data.has_key?('MinLength')
169
+ constraints << 'MaxLength' if param_data.has_key?('MaxLength')
170
+ constraints << 'MinValue' if param_data.has_key?('MinValue')
171
+ constraints << 'MaxValue' if param_data.has_key?('MaxValue')
164
172
  if constraints.any?
165
173
  @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid parameter constraint(s): #{Blufin::Terminal::format_invalid(constraints.join(','))}. These don't apply to AWS-Specific parameters."
166
174
  end
167
175
  else
168
- @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid parameter type: #{Blufin::Terminal::format_invalid(data['Type'])}"
176
+ @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid parameter type: #{Blufin::Terminal::format_invalid(param_data['Type'])}"
169
177
  end
170
178
  end
171
179
  # Can only have Max/MinLength if this is a String.
172
- if data.has_key?('MinLength') || data.has_key?('MaxLength') || data.has_key?('AllowedPattern')
173
- unless data['Type'] == 'String'
180
+ if param_data.has_key?('MinLength') || param_data.has_key?('MaxLength') || param_data.has_key?('AllowedPattern')
181
+ unless param_data['Type'] == 'String'
174
182
  constraints = []
175
- constraints << 'MinLength' if data.has_key?('MinLength')
176
- constraints << 'MaxLength' if data.has_key?('MaxLength')
177
- constraints << 'AllowedPattern' if data.has_key?('AllowedPattern')
183
+ constraints << 'MinLength' if param_data.has_key?('MinLength')
184
+ constraints << 'MaxLength' if param_data.has_key?('MaxLength')
185
+ constraints << 'AllowedPattern' if param_data.has_key?('AllowedPattern')
178
186
  @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid parameter constraint(s): #{Blufin::Terminal::format_invalid(constraints.join(','))}. To use these, type must be String."
179
187
  end
180
188
  end
181
189
  # Can only have Max/MinValue if this is a Number.
182
- if data.has_key?('MinValue') || data.has_key?('MaxValue')
183
- unless data['Type'] == 'Number'
190
+ if param_data.has_key?('MinValue') || param_data.has_key?('MaxValue')
191
+ unless param_data['Type'] == 'Number'
184
192
  constraints = []
185
- constraints << 'MinValue' if data.has_key?('MinValue')
186
- constraints << 'MaxValue' if data.has_key?('MaxValue')
193
+ constraints << 'MinValue' if param_data.has_key?('MinValue')
194
+ constraints << 'MaxValue' if param_data.has_key?('MaxValue')
187
195
  @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Invalid parameter constraint(s): #{Blufin::Terminal::format_invalid(constraints.join(','))}. To use these, type must be Number."
188
196
  end
189
197
  end
190
198
  # If Allowed Values is set, certain conditions must apply.
191
- if data.has_key?('AllowedValues')
199
+ if param_data.has_key?('AllowedValues')
192
200
  %w(AllowedPattern MinLength MaxLength MinValue MaxValue).each do |invalid_key|
193
- if data.has_key?(invalid_key)
194
- @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 AllowedValues is set so cannot have: #{Blufin::Terminal::format_invalid(data['invalid_key'])}"
201
+ if param_data.has_key?(invalid_key)
202
+ @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 AllowedValues is set so cannot have: #{Blufin::Terminal::format_invalid(param_data['invalid_key'])}"
195
203
  end
196
204
  end
197
205
  # Must be Array.
198
- unless data['AllowedValues'].is_a?(Array)
199
- @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 AllowedValues must be Array, instead got: #{Blufin::Terminal::format_invalid(data['AllowedValues'].class)}"
206
+ unless param_data['AllowedValues'].is_a?(Array)
207
+ @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)}"
200
208
  end
201
209
  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
202
215
  end
203
216
  end
204
217
  # Validate description (if exists).
205
218
  if yml_data.has_key?(OPTION_DESCRIPTION)
206
219
  description = yml_data[OPTION_DESCRIPTION]
207
220
  # Validate replaceable value(s) exist.
208
- matches = description.scan(/{{[A-Za-z0-9]+}}/)
221
+ matches = description.scan(/{{[A-Za-z0-9]+}}/)
209
222
  matches.each do |match|
210
223
  match = match.gsub(/^{{/, '').gsub(/}}$/, '')
211
224
  unless parameters.keys.include?(match)
@@ -242,13 +255,14 @@ module AppCommand
242
255
  constant = constant.to_s
243
256
  expected_constants.delete(constant) if expected_constants.include?(constant)
244
257
  # Optional constants.
245
- intro = Template::INTRO if constant == 'INTRO'
246
- stack_name = Template::STACK_NAME if constant == 'STACK_NAME'
247
- projects = Template::PROJECTS if constant == 'PROJECTS'
248
- environments = Template::ENVIRONMENTS if constant == 'ENVIRONMENTS'
249
- regions = Template::REGIONS if constant == 'REGIONS'
250
- timeout = Template::TIMEOUT if constant == 'TIMEOUT'
251
- deployment_stack = Template::DEPLOYMENT_STACK if constant == 'DEPLOYMENT_STACK'
258
+ intro = Template::INTRO if constant == 'INTRO'
259
+ stack_name = Template::STACK_NAME if constant == 'STACK_NAME'
260
+ projects = Template::PROJECTS if constant == 'PROJECTS'
261
+ environments = Template::ENVIRONMENTS if constant == 'ENVIRONMENTS'
262
+ regions = Template::REGIONS if constant == 'REGIONS'
263
+ timeout = Template::TIMEOUT if constant == 'TIMEOUT'
264
+ deployment_stack = Template::DEPLOYMENT_STACK if constant == 'DEPLOYMENT_STACK'
265
+ parameters_no_sort = Template::PARAMETERS_NO_SORT if constant == 'PARAMETERS_NO_SORT'
252
266
  end
253
267
  # Validate stack name.
254
268
  if stack_name.nil? || stack_name.strip == ''
@@ -320,6 +334,16 @@ module AppCommand
320
334
  Object.send(:remove_const, :Template)
321
335
  end
322
336
  end
337
+ # Make sure no-sort parameters exist.
338
+ unless parameters_no_sort.nil?
339
+ if parameters_no_sort.is_a?(Array)
340
+ parameters_no_sort.each do |pns|
341
+ @warnings << "\x1B[38;5;196m#{template_name}\x1B[38;5;240m \xe2\x80\x94 Non-existent #{Blufin::Terminal::format_highlight('PARAMETERS_NO_SORT')} parameter: #{Blufin::Terminal::format_invalid(pns)}" unless parameters.keys.include?(pns)
342
+ end
343
+ else
344
+ @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
+ end
346
+ end
323
347
  @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?
324
348
  @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?
325
349
  @templates[category] = {} unless @templates.has_key?(category)
@@ -331,6 +355,7 @@ module AppCommand
331
355
  else
332
356
  @templates[category][template] = {
333
357
  :name => template,
358
+ :path => template_path,
334
359
  :broken => false,
335
360
  :file_cloudformation => file_cloudformation,
336
361
  :file_ruby => file_ruby,
@@ -339,6 +364,7 @@ module AppCommand
339
364
  :method_before_teardown => method_before_teardown,
340
365
  :method_after_teardown => method_after_teardown,
341
366
  :parameters => parameters,
367
+ :parameters_no_sort => parameters_no_sort,
342
368
  :intro => intro,
343
369
  :description => description,
344
370
  :stack_name => stack_name,
@@ -365,8 +391,8 @@ module AppCommand
365
391
 
366
392
  def opts_routing
367
393
 
368
- used_cache = true
369
- showing_tags = false
394
+ used_cache = true
395
+ showing_tags = false
370
396
 
371
397
  # Show prompt to select template.
372
398
  category, template, @template = select_template_prompt
@@ -430,10 +456,10 @@ module AppCommand
430
456
  capabilities_str = nil
431
457
 
432
458
  # Upload the template to S3.
433
- s3_url = App::AWSCloudFormation::upload_cloudformation_template(category, template, @params[OPTION_DESCRIPTION])
459
+ s3_url = App::AWSCloudFormation::upload_cloudformation_template(category, template, @params[OPTION_DESCRIPTION])
434
460
 
435
461
  # Validates the template.
436
- validation = App::AWSCli::cloudformation_stack_validate(@params[OPTION_REGION], s3_url)
462
+ validation = App::AWSCli::cloudformation_stack_validate(@params[OPTION_REGION], s3_url)
437
463
 
438
464
  # Check if validation output is JSON (and output appropriate format).
439
465
  begin
@@ -645,6 +671,10 @@ module AppCommand
645
671
  OPTION_DESCRIPTION => 'Should this stack be protected against accidental Termination?'
646
672
  }
647
673
  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
648
678
  # Get cached values (if exist and parameters haven't changed).
649
679
  # Even a one-character change in a description will invalidate the cache.
650
680
  cache_file = get_cache_file(category, template)
@@ -716,11 +746,11 @@ module AppCommand
716
746
  puts
717
747
  choices = []
718
748
  else
719
- choices = [{ value: 'y', text: 'Select this template' }]
720
- choices << { value: 'Y', text: "Select this template \x1B[38;5;198m(and apply cached values)\x1B[0m" } if @cache_valid
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
721
751
  end
722
752
  # The prompt at the end of the intro.
723
- choices << { value: 'n', text: "\x1B[38;5;240m#{Blufin::Strings::RETURN_CHARACTER}\x1B[0m" }
753
+ choices << {value: 'n', text: "\x1B[38;5;240m#{Blufin::Strings::RETURN_CHARACTER}\x1B[0m"}
724
754
  choice = Blufin::Terminal::prompt_select('What would you like to do?', choices)
725
755
  case choice
726
756
  when 'y'
@@ -767,10 +797,14 @@ module AppCommand
767
797
  end
768
798
  help_text = 'Description (will be displayed in CloudFormation console).'
769
799
  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}"
770
803
  elsif param_name == OPTION_TIMEOUT
771
804
  return param_data[DEFAULT]
772
805
  elsif param_name == OPTION_TERM_PROTECT
773
- return Blufin::Terminal::prompt_yes?('Protect against accidental Termination?')
806
+ # Basically, by default Termination Protection is off (because most of the time your just testing and want to press Enter).
807
+ return !Blufin::Terminal::prompt_yes?("Allow accidental Termination? (type 'n' to enable Termination Protection)")
774
808
  elsif @auto_fetch_resources.has_key?(param_name)
775
809
  # Sort alphabetically.
776
810
  options = fetch_autocomplete_options(param_name, silent: true)
@@ -787,9 +821,11 @@ module AppCommand
787
821
  puts Blufin::Terminal::display_prompt_text(options_text, default_option)
788
822
  return default_option
789
823
  else
790
- # Sort alphabetically.
791
- options.uniq!
792
- options.sort!
824
+ unless @template[:parameters_no_sort].is_a?(Array) && @template[:parameters_no_sort].include?(param_name)
825
+ # Sort alphabetically.
826
+ options.uniq!
827
+ options.sort!
828
+ end
793
829
  # If we have a cached value, make that the first in the options list.
794
830
  options = move_default_option_to_top(options, param_name) if @cache.has_key?(param_name)
795
831
  puts Blufin::Terminal::display_prompt_help(param_data[OPTION_DESCRIPTION]) if param_data.has_key?(OPTION_DESCRIPTION)
@@ -921,6 +957,16 @@ module AppCommand
921
957
  def assemble_params(params)
922
958
  output = []
923
959
  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
924
970
  unless RESERVED_WORDS.include?(key.downcase)
925
971
  output << {
926
972
  'ParameterKey' => key,
@@ -979,7 +1025,7 @@ module AppCommand
979
1025
  # Replaces current random stack suffix with another one.
980
1026
  # @return string
981
1027
  def replace_stack_suffix(current)
982
- current.gsub(/a[0-9a-z]{8}10w17[0-9a-z]{8}x/, random_stack_suffix)
1028
+ current.gsub(/a[0-9a-z]{16}10w17[0-9a-z]{16}x/, random_stack_suffix)
983
1029
  end
984
1030
 
985
1031
  end
data/lib/version.rb CHANGED
@@ -1 +1 @@
1
- AWX_VERSION = '0.4.2'
1
+ AWX_VERSION = '0.5.0'
@@ -22,14 +22,37 @@ mapping:
22
22
  CloudFormation:
23
23
  type: map
24
24
  mapping:
25
- S3Bucket:
26
- required: yes
27
- S3BucketPath:
25
+ Templates:
28
26
  required: yes
29
- S3BucketRegion:
30
- required: yes
31
- TemplatePath:
27
+ type: map
28
+ mapping:
29
+ Local:
30
+ type: map
31
+ mapping:
32
+ Path:
33
+ required: yes
34
+ S3Bucket:
35
+ type: map
36
+ mapping:
37
+ Name:
38
+ required: yes
39
+ Path:
40
+ required: yes
41
+ Region:
42
+ required: yes
43
+ Uploads:
32
44
  required: yes
45
+ type: map
46
+ mapping:
47
+ S3Bucket:
48
+ type: map
49
+ mapping:
50
+ Name:
51
+ required: yes
52
+ Path:
53
+ required: yes
54
+ Region:
55
+ required: yes
33
56
  Defaults:
34
57
  type: map
35
58
  required: yes
@@ -3,10 +3,18 @@ DynamoDBPath: <<-path/to/folder->>
3
3
  Profiles:
4
4
  - Profile: default
5
5
  CloudFormation:
6
- S3Bucket: <<-S3-bucket-name->>
7
- S3BucketPath: <<-S3-bucket-path/to/folder->>
8
- S3BucketRegion: <<-S3-bucket-region->>
9
- TemplatePath: <<-path/to/folder->>
6
+ Templates:
7
+ Local:
8
+ Path: <<-path->>
9
+ S3Bucket:
10
+ Name: <<-S3-bucket-name->>
11
+ Path: <<-S3-bucket-path->>
12
+ Region: <<-S3-bucket-region->>
13
+ Uploads:
14
+ S3Bucket:
15
+ Name: <<-S3-bucket-name->>
16
+ Path: <<-S3-bucket-path->>
17
+ Region: <<-S3-bucket-region->>
10
18
  Defaults:
11
19
  StackName: "{{CATEGORY}}-{{TEMPLATE}}-{{PROJECT}}-{{ENVIRONMENT}}-{{REGION}}-{{UUID}}"
12
20
  Timeout: 60
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.4.2
4
+ version: 0.5.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-08-09 00:00:00.000000000 Z
11
+ date: 2019-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: blufin-lib
@@ -122,7 +122,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: '2.0'
125
+ version: '2.3'
126
126
  required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - ">="
@@ -130,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
130
  version: '0'
131
131
  requirements: []
132
132
  rubyforge_project:
133
- rubygems_version: 2.6.12
133
+ rubygems_version: 2.5.1
134
134
  signing_key:
135
135
  specification_version: 4
136
136
  summary: An AWS-cli wrapper.