moonshot 0.7.7 → 1.0.0.rc1

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/bin/moonshot +11 -0
  3. data/lib/default/Moonfile.rb +0 -0
  4. data/lib/moonshot.rb +33 -6
  5. data/lib/moonshot/always_use_default_source.rb +17 -0
  6. data/lib/moonshot/artifact_repository/s3_bucket_via_github_releases.rb +140 -3
  7. data/lib/moonshot/ask_user_source.rb +38 -0
  8. data/lib/moonshot/build_mechanism/github_release.rb +1 -1
  9. data/lib/moonshot/build_mechanism/script.rb +1 -1
  10. data/lib/moonshot/command.rb +64 -0
  11. data/lib/moonshot/command_line.rb +150 -0
  12. data/lib/moonshot/commands/build.rb +12 -0
  13. data/lib/moonshot/commands/console.rb +19 -0
  14. data/lib/moonshot/commands/create.rb +37 -0
  15. data/lib/moonshot/commands/delete.rb +12 -0
  16. data/lib/moonshot/commands/deploy.rb +12 -0
  17. data/lib/moonshot/commands/doctor.rb +12 -0
  18. data/lib/moonshot/commands/list.rb +16 -0
  19. data/lib/moonshot/commands/new.rb +99 -0
  20. data/lib/moonshot/commands/parameter_arguments.rb +27 -0
  21. data/lib/moonshot/commands/push.rb +12 -0
  22. data/lib/moonshot/commands/ssh.rb +12 -0
  23. data/lib/moonshot/commands/status.rb +12 -0
  24. data/lib/moonshot/commands/update.rb +29 -0
  25. data/lib/moonshot/commands/version.rb +12 -0
  26. data/lib/moonshot/config.rb +0 -0
  27. data/lib/moonshot/controller.rb +106 -42
  28. data/lib/moonshot/controller_config.rb +31 -13
  29. data/lib/moonshot/deployment_mechanism/code_deploy.rb +17 -7
  30. data/lib/moonshot/json_stack_template.rb +17 -0
  31. data/lib/moonshot/parameter_collection.rb +50 -0
  32. data/lib/moonshot/parent_stack_parameter_loader.rb +51 -0
  33. data/lib/moonshot/resources.rb +3 -3
  34. data/lib/moonshot/resources_helper.rb +2 -2
  35. data/lib/moonshot/ssh_command.rb +31 -0
  36. data/lib/moonshot/ssh_config.rb +1 -1
  37. data/lib/moonshot/stack.rb +66 -77
  38. data/lib/moonshot/stack_list_printer.rb +21 -0
  39. data/lib/moonshot/stack_lister.rb +16 -6
  40. data/lib/moonshot/stack_parameter.rb +64 -0
  41. data/lib/moonshot/stack_parameter_printer.rb +3 -49
  42. data/lib/moonshot/stack_template.rb +13 -25
  43. data/lib/moonshot/task.rb +10 -0
  44. data/lib/moonshot/tools/asg_rollout.rb +1 -1
  45. data/lib/moonshot/tools/asg_rollout/instance_health.rb +1 -1
  46. data/lib/moonshot/tools/asg_rollout_config.rb +1 -1
  47. data/lib/moonshot/yaml_stack_template.rb +17 -0
  48. metadata +51 -9
  49. data/lib/moonshot/cli.rb +0 -220
  50. data/lib/moonshot/environment_parser.rb +0 -32
@@ -1,35 +1,53 @@
1
1
  require_relative 'default_strategy'
2
2
  require_relative 'ssh_config'
3
+ require_relative 'task'
4
+ require_relative 'ask_user_source'
3
5
 
4
6
  module Moonshot
5
7
  # Holds configuration for Moonshot::Controller
6
8
  class ControllerConfig
9
+ attr_accessor :additional_tag
10
+ attr_accessor :answer_file
7
11
  attr_accessor :app_name
8
12
  attr_accessor :artifact_repository
9
- attr_accessor :auto_prefix_stack
10
13
  attr_accessor :build_mechanism
11
14
  attr_accessor :deployment_mechanism
15
+ attr_accessor :dev_build_name_proc
12
16
  attr_accessor :environment_name
17
+ attr_accessor :interactive
13
18
  attr_accessor :interactive_logger
14
- attr_accessor :logger
19
+ attr_accessor :parameter_overrides
20
+ attr_accessor :parameters
15
21
  attr_accessor :parent_stacks
22
+ attr_accessor :default_parameter_source
23
+ attr_accessor :parameter_sources
16
24
  attr_accessor :plugins
25
+ attr_accessor :project_root
17
26
  attr_accessor :show_all_stack_events
18
- attr_accessor :parameter_strategy
19
- attr_accessor :ssh_config
20
- attr_accessor :ssh_command
21
27
  attr_accessor :ssh_auto_scaling_group_name
28
+ attr_accessor :ssh_command
29
+ attr_accessor :ssh_config
22
30
  attr_accessor :ssh_instance
23
31
 
24
32
  def initialize
25
- @auto_prefix_stack = true
26
- @interactive_logger = InteractiveLogger.new
27
- @logger = Logger.new(STDOUT)
28
- @parent_stacks = []
29
- @plugins = []
30
- @show_all_stack_events = false
31
- @parameter_strategy = Moonshot::ParameterStrategy::DefaultStrategy.new
32
- @ssh_config = SSHConfig.new
33
+ @default_parameter_source = AskUserSource.new
34
+ @interactive = true
35
+ @interactive_logger = InteractiveLogger.new
36
+ @parameter_overrides = {}
37
+ @parameter_sources = {}
38
+ @parameters = ParameterCollection.new
39
+ @parent_stacks = []
40
+ @plugins = []
41
+ @project_root = Dir.pwd
42
+ @show_all_stack_events = false
43
+ @ssh_config = SSHConfig.new
44
+
45
+ @dev_build_name_proc = lambda do |c|
46
+ ['dev', c.app_name, c.environment_name, Time.now.to_i].join('/')
47
+ end
48
+
49
+ user = ENV.fetch('USER', 'default-user').gsub(/\W/, '')
50
+ @environment_name = "dev-#{user}"
33
51
  end
34
52
  end
35
53
  end
@@ -66,6 +66,9 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
66
66
  end
67
67
 
68
68
  def deploy_hook(artifact_repo, version_name)
69
+ success = true
70
+ deployment_id = nil
71
+
69
72
  ilog.start_threaded 'Creating Deployment' do |s|
70
73
  res = cd_client.create_deployment(
71
74
  application_name: app_name,
@@ -76,8 +79,10 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
76
79
  )
77
80
  deployment_id = res.deployment_id
78
81
  s.continue "Created Deployment #{deployment_id.blue}."
79
- wait_for_deployment(deployment_id, s)
82
+ success = wait_for_deployment(deployment_id, s)
80
83
  end
84
+
85
+ handle_deployment_failure(deployment_id) unless success
81
86
  end
82
87
 
83
88
  def post_delete_hook
@@ -159,13 +164,13 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
159
164
  @asg_logical_ids.each do |asg_logical_id|
160
165
  asg_name = stack.physical_id_for(asg_logical_id)
161
166
  unless asg_name
162
- raise Thor::Error, "Could not find #{asg_logical_id} resource in Stack."
167
+ raise "Could not find #{asg_logical_id} resource in Stack."
163
168
  end
164
169
 
165
170
  groups = as_client.describe_auto_scaling_groups(
166
171
  auto_scaling_group_names: [asg_name])
167
172
  if groups.auto_scaling_groups.empty?
168
- raise Thor::Error, "Could not find ASG #{asg_name}."
173
+ raise "Could not find ASG #{asg_name}."
169
174
  end
170
175
 
171
176
  autoscaling_groups.push(groups.auto_scaling_groups.first)
@@ -219,7 +224,7 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
219
224
  def role
220
225
  iam_client.get_role(role_name: @codedeploy_role).role
221
226
  rescue Aws::IAM::Errors::NoSuchEntity
222
- raise Thor::Error, "Did not find an IAM Role: #{@codedeploy_role}"
227
+ raise "Did not find an IAM Role: #{@codedeploy_role}"
223
228
  end
224
229
 
225
230
  def delete_deployment_group
@@ -240,7 +245,7 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
240
245
  end
241
246
 
242
247
  def wait_for_asg_capacity
243
- ilog.start 'Waiting for AutoScaling Group(s) to reach capacity...' do |s|
248
+ ilog.start_threaded 'Waiting for AutoScaling Group(s) to reach capacity...' do |s|
244
249
  loop do
245
250
  asgs_at_capacity = 0
246
251
  asgs = load_auto_scaling_groups
@@ -260,6 +265,8 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
260
265
  end
261
266
 
262
267
  def wait_for_deployment(id, step)
268
+ success = true
269
+
263
270
  loop do
264
271
  sleep 5
265
272
  info = cd_client.get_deployment(deployment_id: id).deployment_info
@@ -273,9 +280,12 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
273
280
  break
274
281
  when 'Failed', 'Stopped'
275
282
  step.failure "Deployment #{id.blue} failed with status '#{status}'"
276
- handle_deployment_failure(id)
283
+ success = false
284
+ break
277
285
  end
278
286
  end
287
+
288
+ success
279
289
  end
280
290
 
281
291
  def handle_deployment_failure(deployment_id)
@@ -298,7 +308,7 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
298
308
  end
299
309
  end
300
310
 
301
- raise Thor::Error, 'Deployment was unsuccessful!'
311
+ raise 'Deployment was unsuccessful!'
302
312
  end
303
313
 
304
314
  def revision_for_artifact_repo(artifact_repo, version_name)
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+ require_relative 'stack_template'
3
+
4
+ module Moonshot
5
+ # Handles JSON formatted AWS template files.
6
+ class JsonStackTemplate < StackTemplate
7
+ def body
8
+ template_body.to_json
9
+ end
10
+
11
+ private
12
+
13
+ def template_body
14
+ @template_body ||= JSON.parse(File.read(@filename))
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ module Moonshot
2
+ # A Rigid Hash-like structure that only accepts manipulation of
3
+ # parameters defined in the Stack template. Anything else results in
4
+ # an exception.
5
+ class ParameterCollection
6
+ extend Forwardable
7
+
8
+ def_delegators :@hash, :key?, :fetch, :[], :keys, :values
9
+
10
+ def self.from_template(template)
11
+ obj = new
12
+
13
+ template.parameters.each do |stack_parameter|
14
+ obj.add(stack_parameter)
15
+ end
16
+
17
+ obj
18
+ end
19
+
20
+ def initialize
21
+ @hash = {}
22
+ end
23
+
24
+ def []=(key, value)
25
+ raise "Invalid StackParameter #{key}!" unless @hash.key?(key)
26
+
27
+ @hash[key].set(value)
28
+ end
29
+
30
+ def add(parameter)
31
+ raise ArgumentError, 'Can only add StackParameters!' unless parameter.is_a?(StackParameter)
32
+
33
+ @hash[parameter.name] = parameter
34
+ end
35
+
36
+ # What parameters are missing for a CreateStack call, where
37
+ # UsePreviousValue has no meaning.
38
+ def missing_for_create
39
+ # If we haven't set a value, and there is no default, we can't
40
+ # create the stack.
41
+ @hash.values.select { |v| !v.set? && !v.default? }
42
+ end
43
+
44
+ def missing_for_update
45
+ # If we don't have a previous value to use, we haven't set a
46
+ # value, and there is no default, we can't update a stack.
47
+ @hash.values.select { |v| !v.set? && !v.default? && !v.use_previous? }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,51 @@
1
+ module Moonshot
2
+ class ParentStackParameterLoader
3
+ def initialize(config)
4
+ @config = config
5
+ end
6
+
7
+ def load!
8
+ @config.parent_stacks.each do |stack_name|
9
+ count = 0
10
+
11
+ resp = cf_client.describe_stacks(stack_name: stack_name)
12
+ raise "Parent Stack #{stack_name} not found!" unless resp.stacks.size == 1
13
+
14
+ # If there is an input parameters matching a stack output, pass it.
15
+ resp.stacks[0].outputs.each do |output|
16
+ next unless @config.parameters.key?(output.output_key)
17
+ # Our Stack has a Parameter matching this output. Set it's
18
+ # value to the Output's value.
19
+ count += 1
20
+ @config.parameters.fetch(output.output_key).set(output.output_value)
21
+ end
22
+
23
+ puts "Imported #{count} parameters from parent stack #{stack_name.blue}!" if count > 0
24
+ end
25
+ end
26
+
27
+ def load_missing_only!
28
+ @config.parent_stacks.each do |stack_name|
29
+ resp = cf_client.describe_stacks(stack_name: stack_name)
30
+ raise "Parent Stack #{stack_name} not found!" unless resp.stacks.size == 1
31
+
32
+ # If there is an input parameters matching a stack output, pass it.
33
+ resp.stacks[0].outputs.each do |output|
34
+ next unless @config.parameters.key?(output.output_key)
35
+ # Our Stack has a Parameter matching this output. Set it's
36
+ # value to the Output's value, but only if we don't already
37
+ # have a previous value we're using.
38
+ unless @config.parameters.fetch(output.output_key).use_previous?
39
+ @config.parameters.fetch(output.output_key).set(output.output_value)
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def cf_client
48
+ Aws::CloudFormation::Client.new
49
+ end
50
+ end
51
+ end
@@ -2,12 +2,12 @@ module Moonshot
2
2
  # Resources is a dependency container that holds references to instances
3
3
  # provided to a Mechanism (build, deploy, etc.).
4
4
  class Resources
5
- attr_reader :log, :stack, :ilog
5
+ attr_reader :stack, :ilog, :controller
6
6
 
7
- def initialize(log:, stack:, ilog:)
8
- @log = log
7
+ def initialize(stack:, ilog:, controller:)
9
8
  @stack = stack
10
9
  @ilog = ilog
10
+ @controller = controller
11
11
  end
12
12
  end
13
13
  end
@@ -6,9 +6,9 @@ module Moonshot
6
6
 
7
7
  private
8
8
 
9
+ # TODO: Deprecate this interface.
9
10
  def log
10
- raise 'Resources not provided to Mechanism!' unless @resources
11
- @resources.log
11
+ @log ||= Logger.new(STDOUT)
12
12
  end
13
13
 
14
14
  def stack
@@ -0,0 +1,31 @@
1
+ require 'thor'
2
+
3
+ module Moonshot
4
+ # A SSHCommand that is automatically registered with the
5
+ # Moonshot::CommandLine, including options for SSH access.
6
+ class SSHCommand < Moonshot::Command
7
+ def parser
8
+ parser = super
9
+ parser.on('-l', '--user USER', 'User to log into remote machine as') do |v|
10
+ Moonshot.config.ssh_config.ssh_user = v
11
+ end
12
+
13
+ parser.on('-i', '--identity-file FILE', 'SSH Private Key to authenticate with') do |v|
14
+ Moonshot.config.ssh_config.ssh_identity_file = v
15
+ end
16
+
17
+ parser.on('-s', '--instance INSTANCE_ID', 'Specific AWS EC2 ID to connect through') do |v|
18
+ Moonshot.config.ssh_instance = v
19
+ end
20
+
21
+ parser.on('-c', '--command COMMAND', 'Command to execute on the remote host') do |v|
22
+ Moonshot.config.ssh_command = v
23
+ end
24
+
25
+ parser.on('-g', '--auto-scaling-group ASG_NAME',
26
+ 'The logical ID of the ASG to SSH into, required for multiple stacks') do |v|
27
+ Moonshot.config.ssh_auto_scaling_group_name = v
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,5 @@
1
1
  module Moonshot
2
- class SSHConfig # rubocop:disable Documentation
2
+ class SSHConfig
3
3
  attr_accessor :ssh_identity_file
4
4
  attr_accessor :ssh_user
5
5
  end
@@ -1,7 +1,8 @@
1
1
  require_relative 'creds_helper'
2
2
  require_relative 'doctor_helper'
3
3
 
4
- require_relative 'stack_template'
4
+ require_relative 'yaml_stack_template'
5
+ require_relative 'json_stack_template'
5
6
  require_relative 'stack_parameter_printer'
6
7
  require_relative 'stack_output_printer'
7
8
  require_relative 'stack_asg_printer'
@@ -20,19 +21,15 @@ module Moonshot
20
21
  attr_reader :app_name
21
22
  attr_reader :name
22
23
 
23
- # TODO: Refactor more of these parameters into the config object.
24
- def initialize(name, app_name:, log:, ilog:, config: StackConfig.new)
25
- @name = name
26
- @app_name = app_name
27
- @log = log
28
- @ilog = ilog
24
+ def initialize(config)
29
25
  @config = config
26
+ @ilog = config.interactive_logger
27
+ @name = [@config.app_name, @config.environment_name].join('-')
28
+
30
29
  yield @config if block_given?
31
30
  end
32
31
 
33
32
  def create
34
- import_parent_parameters
35
-
36
33
  should_wait = true
37
34
  @ilog.start "Creating #{stack_name}." do |s|
38
35
  if stack_exists?
@@ -48,7 +45,7 @@ module Moonshot
48
45
  end
49
46
 
50
47
  def update
51
- raise Thor::Error, "No stack found #{@name.blue}!" unless stack_exists?
48
+ raise "No stack found #{@name.blue}!" unless stack_exists?
52
49
 
53
50
  should_wait = true
54
51
  @ilog.start "Updating #{stack_name}." do |s|
@@ -61,7 +58,7 @@ module Moonshot
61
58
  end
62
59
 
63
60
  success = should_wait ? wait_for_stack_state(:stack_update_complete, 'updated') : true
64
- raise Thor::Error, 'Failed to update the CloudFormation Stack.' unless success
61
+ raise 'Failed to update the CloudFormation Stack.' unless success
65
62
  success
66
63
  end
67
64
 
@@ -147,31 +144,32 @@ module Moonshot
147
144
  # Return a Hash of the default values defined in the stack template.
148
145
  def default_values
149
146
  h = {}
150
- JSON.parse(template.body).fetch('Parameters', {}).map do |k, v|
151
- h[k] = v['Default']
147
+ template.parameters.each do |p|
148
+ h[p.name] = h.default
152
149
  end
153
150
  h
154
151
  end
155
152
 
156
153
  def template
157
- @template ||= StackTemplate.new(template_file, log: @log)
154
+ @template ||= load_template_file
158
155
  end
159
156
 
160
157
  # @return [String] the path to the template file.
161
158
  def template_file
162
- File.join(Dir.pwd, 'cloud_formation', "#{@app_name}.json")
159
+ json = json_template_path
160
+ yaml = yaml_template_path
161
+
162
+ @template_file ||= Dir[json].first || Dir[yaml].first
163
+
164
+ raise 'CloudFormation template not found at'\
165
+ "#{json} or #{yaml}!" unless @template_file
166
+
167
+ @template_file
163
168
  end
164
169
 
165
170
  # @return [String] the path to the parameters file.
166
171
  def parameters_file
167
- File.join(Dir.pwd, 'cloud_formation', 'parameters', "#{@name}.yml")
168
- end
169
-
170
- def add_parameter_overrides(hash)
171
- new_overrides = hash.merge(overrides)
172
- File.open(parameters_file, 'w') do |f|
173
- YAML.dump(new_overrides, f)
174
- end
172
+ File.join(@config.project_root, 'cloud_formation', 'parameters', "#{@name}.yml")
175
173
  end
176
174
 
177
175
  private
@@ -180,63 +178,46 @@ module Moonshot
180
178
  "CloudFormation Stack #{@name.blue}"
181
179
  end
182
180
 
183
- def load_parameters_file
184
- @ilog.msg "Loading stack parameters file '#{parameters_file}'."
185
- result = stack_parameter_overrides
186
-
187
- if result.empty?
188
- @ilog.msg "No parameters file for #{@name.blue}, using defaults."
189
- return result
190
- end
191
-
192
- @ilog.msg 'Setting stack parameter overrides:'
193
- result.each do |e|
194
- @ilog.msg " #{e[:parameter_key]}: #{e[:parameter_value]}"
195
- end
181
+ def json_template_path
182
+ "#{raw_template_file_name}.json"
196
183
  end
197
184
 
198
- def stack_parameter_overrides
199
- overrides.map do |k, v|
200
- { parameter_key: k, parameter_value: v.to_s }
201
- end
185
+ def yaml_template_path
186
+ "#{raw_template_file_name}.yml"
202
187
  end
203
188
 
204
- def stack_parameters
205
- @stack_parameters ||= JSON.parse(template.body).fetch('Parameters', {}).keys
189
+ # @return [String] the path to the template file without extension.
190
+ def raw_template_file_name
191
+ @raw_template_file_name ||=
192
+ File.join(@config.project_root, 'cloud_formation', @config.app_name)
206
193
  end
207
194
 
208
- def import_parent_parameters
209
- add_parameter_overrides(parent_stack_outputs)
210
- end
211
-
212
- # Return a Hash of parent stack outputs that match parameter names for this
213
- # stack.
214
- def parent_stack_outputs
215
- result = {}
216
-
217
- @config.parent_stacks.each do |stack_name|
218
- resp = cf_client.describe_stacks(stack_name: stack_name)
219
- raise "Parent Stack #{stack_name} not found!" unless resp.stacks.size == 1
220
-
221
- # If there is an input parameters matching a stack output, pass it.
222
- resp.stacks[0].outputs.each do |output|
223
- if stack_parameters.include?(output.output_key)
224
- result[output.output_key] = output.output_value
225
- end
226
- end
195
+ def load_template_file
196
+ json_template = JsonStackTemplate.new(json_template_path)
197
+ yaml_template = YamlStackTemplate.new(yaml_template_path)
198
+ case
199
+ when json_template.exist?
200
+ json_template
201
+ when yaml_template.exist?
202
+ yaml_template
203
+ else
204
+ raise "CloudFormation template not found at #{json_template_path} "\
205
+ "or #{yaml_template_path}!" unless @template_file
227
206
  end
207
+ end
228
208
 
229
- result
209
+ def stack_parameters
210
+ template.parameters.map(&:name)
230
211
  end
231
212
 
232
213
  # @return [Aws::CloudFormation::Types::Stack]
233
214
  def get_stack(name)
234
215
  stacks = cf_client.describe_stacks(stack_name: name).stacks
235
- raise Thor::Error, "Could not describe stack: #{name}" if stacks.empty?
216
+ raise "Could not describe stack: #{name}" if stacks.empty?
236
217
 
237
218
  stacks.first
238
219
  rescue Aws::CloudFormation::Errors::ValidationError
239
- raise Thor::Error, "Could not describe stack: #{name}"
220
+ raise "Could not describe stack: #{name}"
240
221
  end
241
222
 
242
223
  def create_stack
@@ -244,13 +225,11 @@ module Moonshot
244
225
  stack_name: @name,
245
226
  template_body: template.body,
246
227
  capabilities: ['CAPABILITY_IAM'],
247
- parameters: load_parameters_file,
248
- tags: [
249
- { key: 'ah_stage', value: @name }
250
- ]
228
+ parameters: @config.parameters.values.map(&:to_cf),
229
+ tags: make_tags
251
230
  )
252
231
  rescue Aws::CloudFormation::Errors::AccessDenied
253
- raise Thor::Error, 'You are not authorized to perform create_stack calls.'
232
+ raise 'You are not authorized to perform create_stack calls.'
254
233
  end
255
234
 
256
235
  # @return [Boolean]
@@ -260,27 +239,24 @@ module Moonshot
260
239
  stack_name: @name,
261
240
  template_body: template.body,
262
241
  capabilities: ['CAPABILITY_IAM'],
263
- parameters: @config.parameter_strategy.parameters(
264
- overrides,
265
- parameters,
266
- template
267
- )
242
+ parameters: @config.parameters.values.map(&:to_cf),
243
+ tags: make_tags
268
244
  )
269
245
  true
270
246
  rescue Aws::CloudFormation::Errors::ValidationError => e
271
- raise Thor::Error, e.message unless
247
+ raise e.message unless
272
248
  e.message == 'No updates are to be performed.'
273
249
  false
274
250
  end
275
251
 
276
252
  # TODO: Refactor this into it's own class.
277
- def wait_for_stack_state(wait_target, past_tense_verb) # rubocop:disable AbcSize
253
+ def wait_for_stack_state(wait_target, past_tense_verb)
278
254
  result = true
279
255
 
280
256
  stack_id = get_stack(@name).stack_id
281
257
 
282
258
  events = StackEventsPoller.new(cf_client, stack_id)
283
- events.show_only_errors unless @config.show_all_events
259
+ events.show_only_errors unless @config.show_all_stack_events
284
260
 
285
261
  @ilog.start_threaded "Waiting for #{stack_name} to be successfully #{past_tense_verb}." do |s|
286
262
  begin
@@ -318,6 +294,19 @@ module Moonshot
318
294
  result
319
295
  end
320
296
 
297
+ def make_tags
298
+ default_tags = [
299
+ { key: 'moonshot_application', value: @config.app_name },
300
+ { key: 'moonshot_environment', value: @config.environment_name }
301
+ ]
302
+
303
+ if @config.additional_tag
304
+ default_tags << { key: @config.additional_tag, value: @name }
305
+ end
306
+
307
+ default_tags
308
+ end
309
+
321
310
  def format_event(event)
322
311
  str = case event.resource_status
323
312
  when /FAILED/