moonshot 0.7.7 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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/
|