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.
- checksums.yaml +4 -4
- data/bin/moonshot +11 -0
- data/lib/default/Moonfile.rb +0 -0
- data/lib/moonshot.rb +33 -6
- data/lib/moonshot/always_use_default_source.rb +17 -0
- data/lib/moonshot/artifact_repository/s3_bucket_via_github_releases.rb +140 -3
- data/lib/moonshot/ask_user_source.rb +38 -0
- data/lib/moonshot/build_mechanism/github_release.rb +1 -1
- data/lib/moonshot/build_mechanism/script.rb +1 -1
- data/lib/moonshot/command.rb +64 -0
- data/lib/moonshot/command_line.rb +150 -0
- data/lib/moonshot/commands/build.rb +12 -0
- data/lib/moonshot/commands/console.rb +19 -0
- data/lib/moonshot/commands/create.rb +37 -0
- data/lib/moonshot/commands/delete.rb +12 -0
- data/lib/moonshot/commands/deploy.rb +12 -0
- data/lib/moonshot/commands/doctor.rb +12 -0
- data/lib/moonshot/commands/list.rb +16 -0
- data/lib/moonshot/commands/new.rb +99 -0
- data/lib/moonshot/commands/parameter_arguments.rb +27 -0
- data/lib/moonshot/commands/push.rb +12 -0
- data/lib/moonshot/commands/ssh.rb +12 -0
- data/lib/moonshot/commands/status.rb +12 -0
- data/lib/moonshot/commands/update.rb +29 -0
- data/lib/moonshot/commands/version.rb +12 -0
- data/lib/moonshot/config.rb +0 -0
- data/lib/moonshot/controller.rb +106 -42
- data/lib/moonshot/controller_config.rb +31 -13
- data/lib/moonshot/deployment_mechanism/code_deploy.rb +17 -7
- data/lib/moonshot/json_stack_template.rb +17 -0
- data/lib/moonshot/parameter_collection.rb +50 -0
- data/lib/moonshot/parent_stack_parameter_loader.rb +51 -0
- data/lib/moonshot/resources.rb +3 -3
- data/lib/moonshot/resources_helper.rb +2 -2
- data/lib/moonshot/ssh_command.rb +31 -0
- data/lib/moonshot/ssh_config.rb +1 -1
- data/lib/moonshot/stack.rb +66 -77
- data/lib/moonshot/stack_list_printer.rb +21 -0
- data/lib/moonshot/stack_lister.rb +16 -6
- data/lib/moonshot/stack_parameter.rb +64 -0
- data/lib/moonshot/stack_parameter_printer.rb +3 -49
- data/lib/moonshot/stack_template.rb +13 -25
- data/lib/moonshot/task.rb +10 -0
- data/lib/moonshot/tools/asg_rollout.rb +1 -1
- data/lib/moonshot/tools/asg_rollout/instance_health.rb +1 -1
- data/lib/moonshot/tools/asg_rollout_config.rb +1 -1
- data/lib/moonshot/yaml_stack_template.rb +17 -0
- metadata +51 -9
- data/lib/moonshot/cli.rb +0 -220
- 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 :
|
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
|
-
@
|
26
|
-
@
|
27
|
-
@
|
28
|
-
@
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
32
|
-
@
|
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
|
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
|
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
|
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.
|
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
|
-
|
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
|
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
|
data/lib/moonshot/resources.rb
CHANGED
@@ -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 :
|
5
|
+
attr_reader :stack, :ilog, :controller
|
6
6
|
|
7
|
-
def initialize(
|
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
|
@@ -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
|
data/lib/moonshot/ssh_config.rb
CHANGED
data/lib/moonshot/stack.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require_relative 'creds_helper'
|
2
2
|
require_relative 'doctor_helper'
|
3
3
|
|
4
|
-
require_relative '
|
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
|
-
|
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
|
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
|
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
|
-
|
151
|
-
h[
|
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 ||=
|
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
|
-
|
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(
|
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
|
184
|
-
|
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
|
199
|
-
|
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
|
-
|
205
|
-
|
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
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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
|
-
|
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
|
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
|
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:
|
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
|
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.
|
264
|
-
|
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
|
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)
|
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.
|
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/
|