moonshot 2.0.0.beta2 → 2.0.0.beta3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/default/appspec.yml +12 -0
- data/lib/default/bin/build.sh +15 -0
- data/lib/default/moonshot/template.yml +5 -0
- data/lib/moonshot/artifact_repository/s3_bucket_via_github_releases.rb +9 -7
- data/lib/moonshot/build_mechanism/github_release.rb +42 -12
- data/lib/moonshot/build_mechanism/travis_deploy.rb +10 -24
- data/lib/moonshot/change_set.rb +9 -3
- data/lib/moonshot/commands/deploy.rb +8 -0
- data/lib/moonshot/commands/parent_stack_option.rb +5 -0
- data/lib/moonshot/commands/update.rb +5 -1
- data/lib/moonshot/controller.rb +11 -8
- data/lib/moonshot/controller_config.rb +1 -0
- data/lib/moonshot/creds_helper.rb +12 -12
- data/lib/moonshot/deployment_mechanism/code_deploy.rb +33 -3
- data/lib/moonshot/shell.rb +32 -1
- data/lib/moonshot/stack.rb +3 -3
- data/lib/moonshot/stack_asg_printer.rb +5 -1
- data/lib/moonshot/stack_output_printer.rb +3 -2
- data/lib/plugins/backup.rb +7 -4
- data/lib/plugins/code_deploy_setup.rb +56 -0
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36e066b2e7b8b790bbdf2a6ae2f0ff2b460be924
|
4
|
+
data.tar.gz: ca20969b8fe43fe8cf7296ab3559a9af2132505c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afd2ff66f8f3892cebd6c66c32c90af442eb2d518b86b2c6fd315da716dba8d5097a0c16f9563ad3f85ba6664d905a1dfc0e4790c03ed83eac5288f75f0072c6
|
7
|
+
data.tar.gz: 76667b1b524cabecd1b6994c29d5ecc7b38e80fb92bfcce9d55f6620d4d1566873d612d6177ce58ca50136116e898415e4b2d74d3b2c7bc9fe3cd2ca163f1cb1
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
echo "Building version '$VERSION_NAME', using target file '$OUTPUT_FILE'."
|
4
|
+
|
5
|
+
# Add code here to assemble your project into a compressed tarball (.tar.gz)
|
6
|
+
# located at $OUTPUT_FILE. Be sure to include your appspec.yml in the tarball's
|
7
|
+
# root!
|
8
|
+
#
|
9
|
+
# For example:
|
10
|
+
#
|
11
|
+
# mkdir build_dir
|
12
|
+
# rsync -avP path-to-source build_dir/src
|
13
|
+
# cp moonshot/appspec.yml build_dir/
|
14
|
+
# tar czf $OUTPUT_FILE -C build_dir .
|
15
|
+
# rm -rf build_dir
|
@@ -4,6 +4,7 @@ require 'digest'
|
|
4
4
|
require 'securerandom'
|
5
5
|
require 'semantic'
|
6
6
|
require 'tmpdir'
|
7
|
+
require 'retriable'
|
7
8
|
|
8
9
|
module Moonshot::ArtifactRepository
|
9
10
|
# S3 Bucket repository backed by GitHub releases.
|
@@ -115,25 +116,26 @@ module Moonshot::ArtifactRepository
|
|
115
116
|
# @raise [RuntimeError] If the file fails to download correctly after 3
|
116
117
|
# attempts.
|
117
118
|
def download_from_github(version)
|
119
|
+
file_pattern = "*#{version}*.tar.gz"
|
118
120
|
attempts = 0
|
119
|
-
|
121
|
+
|
122
|
+
Retriable.retriable on: RuntimeError do
|
120
123
|
# Make sure the directory is empty before downloading the release.
|
121
124
|
FileUtils.rm(Dir.glob('*'))
|
122
125
|
|
123
126
|
# Download the release and find the actual build file.
|
124
127
|
sh_out("hub release download #{version}")
|
125
|
-
file = Dir.glob("*#{version}*.tar.gz").fetch(0)
|
126
128
|
|
129
|
+
raise "File '#{file_pattern}' not found." if Dir.glob(file_pattern).empty?
|
130
|
+
|
131
|
+
file = Dir.glob(file_pattern).fetch(0)
|
127
132
|
unless (checksum = checksum_file(file)).nil?
|
128
133
|
verify_download_checksum(file, checksum, attempt: attempts)
|
129
134
|
end
|
130
|
-
rescue RuntimeError => e
|
131
135
|
attempts += 1
|
132
|
-
retry unless attempts > 3
|
133
|
-
raise e
|
134
|
-
end
|
135
136
|
|
136
|
-
|
137
|
+
file
|
138
|
+
end
|
137
139
|
end
|
138
140
|
|
139
141
|
# Find the checksum file for a release, if there is one.
|
@@ -17,8 +17,10 @@ module Moonshot::BuildMechanism
|
|
17
17
|
def_delegator :@build_mechanism, :output_file
|
18
18
|
|
19
19
|
# @param build_mechanism Delegates building after GitHub release is created.
|
20
|
-
def initialize(build_mechanism)
|
20
|
+
def initialize(build_mechanism, ci_status_timeout: 600, max_tag_find_timeout: 240)
|
21
21
|
@build_mechanism = build_mechanism
|
22
|
+
@ci_status_timeout = ci_status_timeout
|
23
|
+
@max_tag_find_timeout = max_tag_find_timeout
|
22
24
|
end
|
23
25
|
|
24
26
|
def doctor_hook
|
@@ -113,13 +115,12 @@ module Moonshot::BuildMechanism
|
|
113
115
|
def git_push_tag(remote, tag)
|
114
116
|
cmd = "git push #{remote} refs/tags/#{tag}:refs/tags/#{tag}"
|
115
117
|
sh_step(cmd) do
|
116
|
-
|
118
|
+
hub_find_remote_tag(tag)
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
120
122
|
def hub_create_release(semver, commitish, changelog_entry)
|
121
123
|
return if hub_release_exists(semver)
|
122
|
-
|
123
124
|
message = "#{semver}\n\n#{changelog_entry}"
|
124
125
|
cmd = "hub release create #{semver} --commitish=#{commitish}"
|
125
126
|
cmd << ' --prerelease' if semver.pre || semver.build
|
@@ -133,11 +134,24 @@ module Moonshot::BuildMechanism
|
|
133
134
|
#
|
134
135
|
# @return [Boolean]
|
135
136
|
def hub_release_exists(semver)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
exists = false
|
138
|
+
sh_step("hub release show #{semver}", fail: false) do |_, output|
|
139
|
+
first_line = output.split("\n").first
|
140
|
+
exists = !first_line.nil? && first_line.strip == semver.to_s
|
141
|
+
end
|
142
|
+
log.info("release #{semver} already exists") if exists
|
143
|
+
exists
|
144
|
+
end
|
145
|
+
|
146
|
+
# Attempt to find the build. Rescue and re-attempt if the build can not
|
147
|
+
# be found on github yet.
|
148
|
+
def hub_find_remote_tag(tag_name)
|
149
|
+
retry_opts = {
|
150
|
+
max_elapsed_time: @max_tag_find_timeout,
|
151
|
+
multiplier: 2
|
152
|
+
}
|
153
|
+
sh_retry("hub ls-remote --exit-code --tags upstream #{tag_name}",
|
154
|
+
opts: retry_opts)
|
141
155
|
end
|
142
156
|
|
143
157
|
def validate_commit
|
@@ -145,10 +159,7 @@ module Moonshot::BuildMechanism
|
|
145
159
|
sh_step(cmd, msg: "Validate commit #{@sha}.") do |_, out|
|
146
160
|
@commit_detail = out
|
147
161
|
end
|
148
|
-
|
149
|
-
sh_step(cmd, msg: "Check CI status for #{@sha}.") do |_, out|
|
150
|
-
@ci_statuses = out
|
151
|
-
end
|
162
|
+
@ci_statuses = check_ci_status(@sha)
|
152
163
|
end
|
153
164
|
|
154
165
|
def validate_changelog(version)
|
@@ -170,6 +181,25 @@ module Moonshot::BuildMechanism
|
|
170
181
|
end
|
171
182
|
end
|
172
183
|
|
184
|
+
# Checks for the commit's CI job status. If its not finished yet,
|
185
|
+
# wait till timeout.
|
186
|
+
#
|
187
|
+
# @param sha [String] Commit sha.
|
188
|
+
#
|
189
|
+
# @return [String] Status and links to the CI jobs
|
190
|
+
def check_ci_status(sha)
|
191
|
+
out = nil
|
192
|
+
retry_opts = {
|
193
|
+
max_elapsed_time: @ci_status_timeout,
|
194
|
+
base_interval: 10
|
195
|
+
}
|
196
|
+
ilog.start_threaded("Check CI status for #{sha}.") do |step|
|
197
|
+
out = sh_retry("hub ci-status --verbose #{sha}", opts: retry_opts)
|
198
|
+
step.success
|
199
|
+
end
|
200
|
+
out
|
201
|
+
end
|
202
|
+
|
173
203
|
def releases_url
|
174
204
|
`hub browse -u -- releases`.chomp
|
175
205
|
end
|
@@ -68,32 +68,18 @@ module Moonshot::BuildMechanism
|
|
68
68
|
#
|
69
69
|
# @return [String] Job number for the travis build.
|
70
70
|
def wait_for_build(version)
|
71
|
+
# Attempt to find the build. Re-attempt if the build can not
|
72
|
+
# be found on travis yet.
|
73
|
+
retry_opts = {
|
74
|
+
tries: MAX_BUILD_FIND_ATTEMPTS,
|
75
|
+
base_interval: 10
|
76
|
+
}
|
71
77
|
job_number = nil
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
sleep 10
|
77
|
-
|
78
|
-
# Attempt to find the build. Rescue and re-attempt if the build can not
|
79
|
-
# be found on travis yet.
|
80
|
-
begin
|
81
|
-
build_out = sh_out("bundle exec travis show #{@cli_args} #{version}")
|
82
|
-
rescue RuntimeError => e
|
83
|
-
next unless attempts >= MAX_BUILD_FIND_ATTEMPTS
|
84
|
-
raise e
|
85
|
-
end
|
86
|
-
|
87
|
-
unless (job_number = build_out.match(/^#(\d+\.\d+) .+BUILD=1.+/)[1])
|
88
|
-
next unless attempts >= MAX_BUILD_FIND_ATTEMPTS
|
89
|
-
raise "Build for #{version} not found.\n#{build_out}"
|
90
|
-
end
|
91
|
-
|
92
|
-
# If we've reached this point then everything went smoothly and we can
|
93
|
-
# exit the loop.
|
94
|
-
break
|
78
|
+
sh_retry("bundle exec travis show #{@cli_args} #{version}",
|
79
|
+
opts: retry_opts) do |build_out|
|
80
|
+
raise CommandError, "Build for #{version} not found.\n#{build_out}" \
|
81
|
+
unless (job_number = build_out.match(/^#(\d+\.\d+) .+BUILD=1.+/)[1])
|
95
82
|
end
|
96
|
-
|
97
83
|
job_number
|
98
84
|
end
|
99
85
|
|
data/lib/moonshot/change_set.rb
CHANGED
@@ -76,7 +76,10 @@ module Moonshot
|
|
76
76
|
# NOTE: At the time of this patch, AWS-SDK native Waiters do not
|
77
77
|
# have support for ChangeSets. Once they add this, we can make
|
78
78
|
# this code much better.
|
79
|
+
# Still no support for this waiter, but it's planned.
|
80
|
+
# https://github.com/aws/aws-sdk-ruby/issues/1388
|
79
81
|
def wait_for_change_set
|
82
|
+
wait_seconds = Moonshot.config.changeset_wait_time || 90
|
80
83
|
start = Time.now.to_i
|
81
84
|
|
82
85
|
loop do
|
@@ -89,11 +92,14 @@ module Moonshot
|
|
89
92
|
return
|
90
93
|
end
|
91
94
|
|
92
|
-
if Time.now.to_i > start +
|
93
|
-
raise
|
95
|
+
if Time.now.to_i > start + wait_seconds
|
96
|
+
raise "ChangeSet did not complete creation within #{wait_seconds} seconds!"
|
94
97
|
end
|
95
98
|
|
96
|
-
sleep
|
99
|
+
sleep 5 # http://bit.ly/1qY1ZXJ
|
100
|
+
# Wait 5 seconds because other waiters seem to wait at least 5 seconds
|
101
|
+
# before repeating requests.
|
102
|
+
# See: https://github.com/aws/aws-sdk-ruby/blob/master/aws-sdk-core/apis/cloudformation/2010-05-15/waiters-2.json#L5
|
97
103
|
end
|
98
104
|
end
|
99
105
|
end
|
@@ -4,6 +4,14 @@ module Moonshot
|
|
4
4
|
self.usage = 'deploy VERSION'
|
5
5
|
self.description = 'Deploy a versioned release to the environment'
|
6
6
|
|
7
|
+
def parser
|
8
|
+
parser = super
|
9
|
+
|
10
|
+
parser.on('--[no-]interactive', TrueClass, 'Use interactive prompts.') do |v|
|
11
|
+
Moonshot.config.interactive = v
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
7
15
|
def execute(version_name)
|
8
16
|
controller.deploy_version(version_name)
|
9
17
|
end
|
@@ -8,6 +8,11 @@ module Moonshot
|
|
8
8
|
'Parent stack to import parameters from') do |v|
|
9
9
|
Moonshot.config.parent_stacks = [v]
|
10
10
|
end
|
11
|
+
|
12
|
+
parser.on('--parents a,b,c', Array,
|
13
|
+
'List of parent stacks to import parameters from') do |v|
|
14
|
+
Moonshot.config.parent_stacks = v
|
15
|
+
end
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
@@ -18,11 +18,15 @@ module Moonshot
|
|
18
18
|
parser.on('--force', '-f', TrueClass, 'Apply ChangeSet without confirmation') do |v|
|
19
19
|
@force = v
|
20
20
|
end
|
21
|
+
|
22
|
+
parser.on('--refresh-parameters', TrueClass, 'Update parameters from parent stacks') do |v|
|
23
|
+
@refresh_parameters = v
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
def execute
|
24
28
|
@force = true unless Moonshot.config.interactive
|
25
|
-
controller.update(dry_run: @dry_run, force: @force)
|
29
|
+
controller.update(dry_run: @dry_run, force: @force, refresh_parameters: @refresh_parameters)
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
data/lib/moonshot/controller.rb
CHANGED
@@ -63,7 +63,7 @@ module Moonshot
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
def update(dry_run:, force:) # rubocop:disable AbcSize
|
66
|
+
def update(dry_run:, force:, refresh_parameters:) # rubocop:disable AbcSize
|
67
67
|
# Scan the template for all required parameters and configure
|
68
68
|
# the ParameterCollection.
|
69
69
|
@config.parameters = ParameterCollection.from_template(stack.template)
|
@@ -75,7 +75,8 @@ module Moonshot
|
|
75
75
|
|
76
76
|
# Import all Outputs from parent stacks as Parameters on this
|
77
77
|
# stack.
|
78
|
-
ParentStackParameterLoader.new(@config)
|
78
|
+
parent_stack_params = ParentStackParameterLoader.new(@config)
|
79
|
+
refresh_parameters ? parent_stack_params.load! : parent_stack_params.load_missing_only!
|
79
80
|
|
80
81
|
# If there is an answer file, use it to populate parameters.
|
81
82
|
if @config.answer_file
|
@@ -91,9 +92,7 @@ module Moonshot
|
|
91
92
|
|
92
93
|
# Interview the user for missing parameters, using the
|
93
94
|
# appropriate prompts.
|
94
|
-
@config.parameters.values.each do |sp|
|
95
|
-
next if sp.set?
|
96
|
-
|
95
|
+
@config.parameters.values.reject(&:set?).each do |sp|
|
97
96
|
parameter_source = @config.parameter_sources.fetch(sp.name,
|
98
97
|
@config.default_parameter_source)
|
99
98
|
parameter_source.get(sp)
|
@@ -153,9 +152,13 @@ module Moonshot
|
|
153
152
|
|
154
153
|
run_plugins(:pre_delete)
|
155
154
|
run_hook(:deploy, :pre_delete)
|
156
|
-
stack.delete
|
157
|
-
|
158
|
-
|
155
|
+
stack_ok = stack.delete
|
156
|
+
if stack_ok # rubocop:disable GuardClause
|
157
|
+
run_hook(:deploy, :post_delete)
|
158
|
+
run_plugins(:post_delete)
|
159
|
+
else
|
160
|
+
raise 'Stack deletion failed!'
|
161
|
+
end
|
159
162
|
end
|
160
163
|
|
161
164
|
def doctor
|
@@ -1,28 +1,28 @@
|
|
1
1
|
module Moonshot
|
2
2
|
# Create convenience methods for various AWS client creation.
|
3
3
|
module CredsHelper
|
4
|
-
def cf_client
|
5
|
-
Aws::CloudFormation::Client.new
|
4
|
+
def cf_client(**args)
|
5
|
+
Aws::CloudFormation::Client.new(args)
|
6
6
|
end
|
7
7
|
|
8
|
-
def cd_client
|
9
|
-
Aws::CodeDeploy::Client.new
|
8
|
+
def cd_client(**args)
|
9
|
+
Aws::CodeDeploy::Client.new(args)
|
10
10
|
end
|
11
11
|
|
12
|
-
def ec2_client
|
13
|
-
Aws::EC2::Client.new
|
12
|
+
def ec2_client(**args)
|
13
|
+
Aws::EC2::Client.new(args)
|
14
14
|
end
|
15
15
|
|
16
|
-
def iam_client
|
17
|
-
Aws::IAM::Client.new
|
16
|
+
def iam_client(**args)
|
17
|
+
Aws::IAM::Client.new(args)
|
18
18
|
end
|
19
19
|
|
20
|
-
def as_client
|
21
|
-
Aws::AutoScaling::Client.new
|
20
|
+
def as_client(**args)
|
21
|
+
Aws::AutoScaling::Client.new(args)
|
22
22
|
end
|
23
23
|
|
24
|
-
def s3_client
|
25
|
-
Aws::S3::Client.new
|
24
|
+
def s3_client(**args)
|
25
|
+
Aws::S3::Client.new(args)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -13,6 +13,8 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
|
|
13
13
|
include Moonshot::CredsHelper
|
14
14
|
include Moonshot::DoctorHelper
|
15
15
|
|
16
|
+
DEFAULT_ROLE_NAME = 'CodeDeployRole'.freeze
|
17
|
+
|
16
18
|
# @param asg [Array, String]
|
17
19
|
# The logical name of the AutoScalingGroup to create and manage a Deployment
|
18
20
|
# Group for in CodeDeploy.
|
@@ -37,7 +39,7 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
|
|
37
39
|
def initialize(
|
38
40
|
asg: [],
|
39
41
|
optional_asg: [],
|
40
|
-
role:
|
42
|
+
role: DEFAULT_ROLE_NAME,
|
41
43
|
app_name: nil,
|
42
44
|
group_name: nil,
|
43
45
|
config_name: 'CodeDeployDefault.OneAtATime')
|
@@ -247,7 +249,35 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
|
|
247
249
|
def role
|
248
250
|
iam_client.get_role(role_name: @codedeploy_role).role
|
249
251
|
rescue Aws::IAM::Errors::NoSuchEntity
|
250
|
-
|
252
|
+
# Auto create the IAM Role if it does not exist in the current AWS account
|
253
|
+
ilog.start "Missing IAM Role: #{@codedeploy_role.blue}. Creating it now ..." do |s|
|
254
|
+
code_deploy_policy = {
|
255
|
+
'Version' => '2012-10-17',
|
256
|
+
'Statement' => [
|
257
|
+
{
|
258
|
+
'Sid' => '',
|
259
|
+
'Effect' => 'Allow',
|
260
|
+
'Principal' => {
|
261
|
+
'Service' => [
|
262
|
+
'codedeploy.amazonaws.com'
|
263
|
+
]
|
264
|
+
},
|
265
|
+
'Action' => 'sts:AssumeRole'
|
266
|
+
}
|
267
|
+
]
|
268
|
+
}
|
269
|
+
|
270
|
+
result = iam_client.create_role(
|
271
|
+
role_name: @codedeploy_role,
|
272
|
+
assume_role_policy_document: code_deploy_policy.to_json
|
273
|
+
)
|
274
|
+
iam_client.attach_role_policy(
|
275
|
+
role_name: @codedeploy_role,
|
276
|
+
policy_arn: 'arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole'
|
277
|
+
)
|
278
|
+
s.success "Created IAM Role successfully: #{@codedeploy_role.blue}"
|
279
|
+
result.role
|
280
|
+
end
|
251
281
|
end
|
252
282
|
|
253
283
|
def delete_deployment_group
|
@@ -372,7 +402,7 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
|
|
372
402
|
end
|
373
403
|
|
374
404
|
def doctor_check_code_deploy_role
|
375
|
-
|
405
|
+
role
|
376
406
|
success("#{@codedeploy_role} exists.")
|
377
407
|
rescue => e
|
378
408
|
help = <<-EOF
|
data/lib/moonshot/shell.rb
CHANGED
@@ -1,7 +1,20 @@
|
|
1
1
|
require 'thor'
|
2
|
+
require 'retriable'
|
2
3
|
|
3
4
|
# Mixin providing the Thor::Shell methods and other shell execution helpers.
|
4
5
|
module Moonshot::Shell
|
6
|
+
CommandError = Class.new(RuntimeError)
|
7
|
+
|
8
|
+
# Retry every 10 seconds for a maximum of 2 minutes.
|
9
|
+
DEFAULT_RETRY_OPTIONS = {
|
10
|
+
on: RuntimeError,
|
11
|
+
tries: 50,
|
12
|
+
multiplier: 1,
|
13
|
+
base_interval: 10,
|
14
|
+
max_elapsed_time: 120,
|
15
|
+
rand_factor: 0
|
16
|
+
}.freeze
|
17
|
+
|
5
18
|
# Run a command, returning stdout. Stderr is suppressed unless the command
|
6
19
|
# returns non-zero.
|
7
20
|
def sh_out(cmd, fail: true, stdin: '')
|
@@ -22,7 +35,7 @@ module Moonshot::Shell
|
|
22
35
|
r_err.close
|
23
36
|
|
24
37
|
if fail && $CHILD_STATUS.exitstatus != 0
|
25
|
-
raise "`#{cmd}` exited #{$CHILD_STATUS.exitstatus}\n" \
|
38
|
+
raise CommandError, "`#{cmd}` exited #{$CHILD_STATUS.exitstatus}\n" \
|
26
39
|
"stdout:\n" \
|
27
40
|
"#{stdout}\n" \
|
28
41
|
"stderr:\n" \
|
@@ -51,4 +64,22 @@ module Moonshot::Shell
|
|
51
64
|
step.success
|
52
65
|
end
|
53
66
|
end
|
67
|
+
|
68
|
+
# Retries every second upto maximum of 2 minutes with the default options.
|
69
|
+
#
|
70
|
+
# @param cmd [String] command to execute.
|
71
|
+
# @param fail [Boolean] Raise error when the command exits with non-zero.
|
72
|
+
# @param stdin [String] Input to the command.
|
73
|
+
# @param opts [Hash] Options for retriable.
|
74
|
+
#
|
75
|
+
# @return [String] Stdout form the command.
|
76
|
+
def sh_retry(cmd, fail: true, stdin: '', opts: {})
|
77
|
+
Retriable.retriable(DEFAULT_RETRY_OPTIONS.merge(opts)) do
|
78
|
+
out = sh_out(cmd, stdin: stdin)
|
79
|
+
yield out if block_given?
|
80
|
+
out
|
81
|
+
end
|
82
|
+
rescue CommandError => e
|
83
|
+
raise e if fail
|
84
|
+
end
|
54
85
|
end
|
data/lib/moonshot/stack.rb
CHANGED
@@ -180,7 +180,7 @@ module Moonshot
|
|
180
180
|
cf_client.create_stack(
|
181
181
|
stack_name: @name,
|
182
182
|
template_body: template.body,
|
183
|
-
capabilities:
|
183
|
+
capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM),
|
184
184
|
parameters: @config.parameters.values.map(&:to_cf),
|
185
185
|
tags: make_tags
|
186
186
|
)
|
@@ -200,7 +200,7 @@ module Moonshot
|
|
200
200
|
description: "Moonshot update command for application '#{Moonshot.config.app_name}'",
|
201
201
|
stack_name: @name,
|
202
202
|
template_body: template.body,
|
203
|
-
capabilities:
|
203
|
+
capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM),
|
204
204
|
parameters: @config.parameters.values.map(&:to_cf)
|
205
205
|
)
|
206
206
|
|
@@ -220,7 +220,7 @@ module Moonshot
|
|
220
220
|
begin
|
221
221
|
cf_client.wait_until(wait_target, stack_name: stack_id) do |w|
|
222
222
|
w.delay = 10
|
223
|
-
w.max_attempts =
|
223
|
+
w.max_attempts = 360 # 60 minutes.
|
224
224
|
w.before_wait do |attempt, resp|
|
225
225
|
begin
|
226
226
|
events.latest_events.each { |e| @ilog.error(format_event(e)) }
|
@@ -112,7 +112,11 @@ module Moonshot
|
|
112
112
|
|
113
113
|
def instance_row(asg_instance, ec2_instance)
|
114
114
|
if ec2_instance
|
115
|
-
|
115
|
+
if ec2_instance.public_ip_address
|
116
|
+
ip_address = "#{ec2_instance.public_ip_address} (#{ec2_instance.private_ip_address})"
|
117
|
+
else
|
118
|
+
ip_address = "#{ec2_instance.private_ip_address} (PRV)"
|
119
|
+
end
|
116
120
|
uptime = uptime_format(ec2_instance.launch_time)
|
117
121
|
else
|
118
122
|
# We've seen race conditions where ASG tells us about instances that EC2 is no longer
|
@@ -8,9 +8,10 @@ module Moonshot
|
|
8
8
|
|
9
9
|
def print
|
10
10
|
o_table = @table.add_leaf('Stack Outputs')
|
11
|
-
@stack.outputs.
|
12
|
-
|
11
|
+
rows = @stack.outputs.sort.map do |key, value|
|
12
|
+
["#{key}:", value]
|
13
13
|
end
|
14
|
+
o_table.add_table(rows)
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
data/lib/plugins/backup.rb
CHANGED
@@ -14,7 +14,8 @@ module Moonshot
|
|
14
14
|
:hooks,
|
15
15
|
:target_name,
|
16
16
|
:backup_parameters,
|
17
|
-
:backup_template
|
17
|
+
:backup_template,
|
18
|
+
:bucket_region
|
18
19
|
|
19
20
|
def initialize
|
20
21
|
yield self if block_given?
|
@@ -99,10 +100,10 @@ module Moonshot
|
|
99
100
|
end
|
100
101
|
|
101
102
|
# adding parameters
|
102
|
-
if @backup_parameters
|
103
|
+
if @backup_parameters && Moonshot.config.answer_file
|
103
104
|
add_str_to_tar(
|
104
105
|
writer,
|
105
|
-
|
106
|
+
Moonshot.config.answer_file,
|
106
107
|
@parameters
|
107
108
|
)
|
108
109
|
end
|
@@ -162,7 +163,9 @@ module Moonshot
|
|
162
163
|
#
|
163
164
|
# @param io_zip [IO] tar stream
|
164
165
|
def upload(io_zip)
|
165
|
-
|
166
|
+
opts = {}
|
167
|
+
opts[:region] = @bucket_region if @bucket_region
|
168
|
+
s3_client(opts).put_object(
|
166
169
|
acl: 'private',
|
167
170
|
bucket: @target_bucket,
|
168
171
|
key: @target_name,
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Moonshot
|
2
|
+
module Plugins
|
3
|
+
# Plugin to ensure CodeDeploy has all necessary S3 buckets created.
|
4
|
+
# Defaults to using ENV['AWS_REGION'] as default region if not configured.
|
5
|
+
class CodeDeploySetup
|
6
|
+
include Moonshot::CredsHelper
|
7
|
+
|
8
|
+
attr_reader :name, :prefix, :regions
|
9
|
+
|
10
|
+
def initialize(name, prefix: '', regions: [ENV['AWS_REGION']])
|
11
|
+
@regions = regions.reject(&:nil?)
|
12
|
+
if @regions.empty?
|
13
|
+
raise ArgumentError, 'CodeDeploySetup requires at least one region.' \
|
14
|
+
' Set regions argument or ENV[\'AWS_REGION\'].'
|
15
|
+
end
|
16
|
+
|
17
|
+
@name = name
|
18
|
+
@prefix = prefix
|
19
|
+
end
|
20
|
+
|
21
|
+
def bucket_name(region = ENV['AWS_REGION'])
|
22
|
+
if ENV.key?('S3_BUCKET')
|
23
|
+
ENV['S3_BUCKET']
|
24
|
+
else
|
25
|
+
"#{@name}-#{region}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def bucket_prefix
|
30
|
+
@prefix.empty? ? '' : "#{@prefix}/"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create an S3 bucket in each supported region for CodeDeploy
|
34
|
+
def setup_code_deploy_s3_buckets
|
35
|
+
@regions.uniq.each do |region|
|
36
|
+
client = s3_client(region: region)
|
37
|
+
name = bucket_name(region)
|
38
|
+
bucket = Aws::S3::Bucket.new(
|
39
|
+
name,
|
40
|
+
client: client
|
41
|
+
)
|
42
|
+
bucket.create unless bucket.exists?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Hook entry points to ensure S3 Buckets are available for CodeDeploy
|
47
|
+
def run_hook(_resources)
|
48
|
+
setup_code_deploy_s3_buckets
|
49
|
+
end
|
50
|
+
|
51
|
+
# Moonshot hooks to trigger this plugin
|
52
|
+
alias pre_create run_hook
|
53
|
+
alias pre_deploy run_hook
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moonshot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cloud Engineering <engineering@acquia.com>
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|
@@ -100,6 +100,20 @@ dependencies:
|
|
100
100
|
- - "~>"
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: 3.2.3
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: retriable
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
103
117
|
- !ruby/object:Gem::Dependency
|
104
118
|
name: activesupport
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -249,6 +263,9 @@ extra_rdoc_files: []
|
|
249
263
|
files:
|
250
264
|
- bin/moonshot
|
251
265
|
- lib/default/Moonfile.rb
|
266
|
+
- lib/default/appspec.yml
|
267
|
+
- lib/default/bin/build.sh
|
268
|
+
- lib/default/moonshot/template.yml
|
252
269
|
- lib/moonshot.rb
|
253
270
|
- lib/moonshot/account_context.rb
|
254
271
|
- lib/moonshot/always_use_default_source.rb
|
@@ -317,6 +334,7 @@ files:
|
|
317
334
|
- lib/moonshot/unicode_table.rb
|
318
335
|
- lib/moonshot/yaml_stack_template.rb
|
319
336
|
- lib/plugins/backup.rb
|
337
|
+
- lib/plugins/code_deploy_setup.rb
|
320
338
|
- lib/plugins/encrypted_parameters.rb
|
321
339
|
- lib/plugins/encrypted_parameters/kms_key.rb
|
322
340
|
- lib/plugins/encrypted_parameters/parameter_encrypter.rb
|