moonshot 1.1.0.beta4 → 2.0.0.beta1
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/moonshot/command_line_dispatcher.rb +2 -1
- data/lib/moonshot/deployment_mechanism/code_deploy.rb +7 -3
- data/lib/plugins/backup.rb +89 -16
- data/lib/plugins/encrypted_parameters.rb +72 -66
- data/lib/plugins/encrypted_parameters/kms_key.rb +17 -15
- data/lib/plugins/encrypted_parameters/parameter_encrypter.rb +18 -16
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d2a30d2ed3a9a3f146a0bcf4972f0bfc9baff41
|
4
|
+
data.tar.gz: 0087b7d90297d013cffd9b787f88b720dc357212
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c1e1938bd414ec74f03185c824cf45e4c3f101b7b4acbaabbec46d71f17bf018b56600201eb1445c6b8b9c14c9c81223819c428a4667f4f67e69a90ddde5ba2
|
7
|
+
data.tar.gz: c7262c61bd51cf6febe8f31cee9a8ef64831580aeaacba2b883725b5f36d38389db5337d456ba693c03249c1f24d68df3c29ab9d47cb088930793dd23aa9cfed
|
@@ -16,7 +16,8 @@ module Moonshot
|
|
16
16
|
parser = build_parser(handler)
|
17
17
|
parser.parse!
|
18
18
|
|
19
|
-
|
19
|
+
req_arguments = handler.method(:execute).parameters.select { |arg| arg[0] == :req }
|
20
|
+
if ARGV.size < req_arguments.size
|
20
21
|
warn handler.parser.help
|
21
22
|
raise "Invalid command line for '#{@command}'."
|
22
23
|
end
|
@@ -307,9 +307,13 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength
|
|
307
307
|
inst_summary.lifecycle_events.each do |event|
|
308
308
|
next unless event.status == 'Failed'
|
309
309
|
|
310
|
-
|
311
|
-
|
312
|
-
|
310
|
+
if event.diagnostics.nil?
|
311
|
+
ilog.error('Lifecycle event chain is not available.')
|
312
|
+
else
|
313
|
+
ilog.error(event.diagnostics.message)
|
314
|
+
event.diagnostics.log_tail.each_line do |line|
|
315
|
+
ilog.error(line)
|
316
|
+
end
|
313
317
|
end
|
314
318
|
end
|
315
319
|
end
|
data/lib/plugins/backup.rb
CHANGED
@@ -1,23 +1,24 @@
|
|
1
1
|
require 'rubygems/package'
|
2
2
|
require 'zlib'
|
3
|
+
require 'yaml'
|
3
4
|
|
4
5
|
module Moonshot
|
5
6
|
module Plugins
|
6
7
|
# Moonshot plugin class for deflating and uploading files on given hooks
|
7
|
-
class Backup
|
8
|
+
class Backup # rubocop:disable Metrics/ClassLength
|
8
9
|
include Moonshot::CredsHelper
|
9
10
|
|
10
11
|
attr_accessor :bucket,
|
11
12
|
:buckets,
|
12
13
|
:files,
|
13
14
|
:hooks,
|
14
|
-
:target_name
|
15
|
+
:target_name,
|
16
|
+
:backup_parameters,
|
17
|
+
:backup_template
|
15
18
|
|
16
19
|
def initialize
|
17
20
|
yield self if block_given?
|
18
|
-
|
19
|
-
if @files.nil? || @files.empty? || @hooks.nil? || !(@bucket.nil? ^ @buckets.nil?)
|
20
|
-
|
21
|
+
validate_configuration
|
21
22
|
@target_name ||= '%{app_name}_%{timestamp}_%{user}.tar.gz'
|
22
23
|
end
|
23
24
|
|
@@ -29,10 +30,8 @@ module Moonshot
|
|
29
30
|
raise ArgumentError if bucket.nil? || bucket.empty?
|
30
31
|
Moonshot::Plugins::Backup.new do |b|
|
31
32
|
b.bucket = bucket
|
32
|
-
b.
|
33
|
-
|
34
|
-
'cloud_formation/parameters/%{stack_name}.yml'
|
35
|
-
]
|
33
|
+
b.backup_parameters = true
|
34
|
+
b.backup_template = true
|
36
35
|
b.hooks = [:post_create, :post_update]
|
37
36
|
end
|
38
37
|
end
|
@@ -44,10 +43,11 @@ module Moonshot
|
|
44
43
|
def backup(resources)
|
45
44
|
raise ArgumentError if resources.nil?
|
46
45
|
|
47
|
-
@app_name = resources.
|
46
|
+
@app_name = resources.controller.config.app_name
|
48
47
|
@stack_name = resources.stack.name
|
49
48
|
@target_name = render(@target_name)
|
50
49
|
@target_bucket = define_bucket
|
50
|
+
@parameters = resources.stack.parameters
|
51
51
|
|
52
52
|
return if @target_bucket.nil?
|
53
53
|
|
@@ -58,7 +58,7 @@ module Moonshot
|
|
58
58
|
upload(zip_out)
|
59
59
|
|
60
60
|
s.success("#{log_message} succeeded.")
|
61
|
-
rescue
|
61
|
+
rescue => e
|
62
62
|
s.failure("#{log_message} failed: #{e}")
|
63
63
|
ensure
|
64
64
|
tar_out.close unless tar_out.nil?
|
@@ -90,18 +90,59 @@ module Moonshot
|
|
90
90
|
def tar(target_files)
|
91
91
|
tar_stream = StringIO.new
|
92
92
|
Gem::Package::TarWriter.new(tar_stream) do |writer|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
93
|
+
# adding user files
|
94
|
+
unless target_files.nil? || target_files.empty?
|
95
|
+
target_files.each do |file|
|
96
|
+
file = render(file)
|
97
|
+
add_file_to_tar(writer, file)
|
98
98
|
end
|
99
99
|
end
|
100
|
+
|
101
|
+
# adding parameters
|
102
|
+
if @backup_parameters
|
103
|
+
add_str_to_tar(
|
104
|
+
writer,
|
105
|
+
render('%{stack_name}-parameters.yml'),
|
106
|
+
@parameters
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
# adding template file
|
111
|
+
if @backup_template
|
112
|
+
template_file_path = render('cloud_formation/%{app_name}.json')
|
113
|
+
add_file_to_tar(writer, template_file_path)
|
114
|
+
end
|
100
115
|
end
|
101
116
|
tar_stream.seek(0)
|
102
117
|
tar_stream
|
103
118
|
end
|
104
119
|
|
120
|
+
# Helper method to add a file to an inmemory tar archive.
|
121
|
+
#
|
122
|
+
# @param writer [TarWriter]
|
123
|
+
# @param file_name [String]
|
124
|
+
def add_file_to_tar(writer, file_name)
|
125
|
+
writer.add_file(File.basename(file_name), 0644) do |io|
|
126
|
+
begin
|
127
|
+
File.open(file_name, 'r') { |f| io.write(f.read) }
|
128
|
+
rescue Errno::ENOENT
|
129
|
+
warn "'#{file_name}' was not found."
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Helper method to add a file based on an input String as content
|
135
|
+
# to an inmemory tar archive.
|
136
|
+
#
|
137
|
+
# @param writer [TarWriter]
|
138
|
+
# @param target_filename [String]
|
139
|
+
# @param content [String]
|
140
|
+
def add_str_to_tar(writer, target_filename, content)
|
141
|
+
writer.add_file(File.basename(target_filename), 0644) do |io|
|
142
|
+
io.write(content.to_yaml)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
105
146
|
# Create a zip archive in memory, returning the IO object pointing at the
|
106
147
|
# beginning of the zipfile.
|
107
148
|
#
|
@@ -168,6 +209,38 @@ module Moonshot
|
|
168
209
|
def bucket_by_account(account)
|
169
210
|
@buckets[account]
|
170
211
|
end
|
212
|
+
|
213
|
+
def validate_configuration
|
214
|
+
validate_buckets
|
215
|
+
validate_redundant_configuration
|
216
|
+
validate_targets
|
217
|
+
validate_hooks
|
218
|
+
end
|
219
|
+
|
220
|
+
def validate_buckets
|
221
|
+
raise ArgumentError, 'You must specify a target bucket.' \
|
222
|
+
if (@bucket.nil? || @bucket.empty?) \
|
223
|
+
&& (@buckets.nil? || @buckets.empty?)
|
224
|
+
end
|
225
|
+
|
226
|
+
def validate_redundant_configuration
|
227
|
+
raise ArgumentError, 'You can not specify both `bucket` and `buckets`.' \
|
228
|
+
if @bucket && @buckets
|
229
|
+
end
|
230
|
+
|
231
|
+
def validate_targets
|
232
|
+
raise ArgumentError, 'You must specify files to back up.' \
|
233
|
+
if (@files.nil? || @files.empty?) \
|
234
|
+
&& (!@backup_parameters && !@backup_template)
|
235
|
+
end
|
236
|
+
|
237
|
+
def validate_hooks
|
238
|
+
raise ArgumentError, 'You must specify a hook / hooks to run the backup on.' \
|
239
|
+
if hooks.nil? || hooks.empty?
|
240
|
+
|
241
|
+
raise ArgumentError, '`pre_create` and `post_delete` hooks are not supported.' \
|
242
|
+
if hooks.include?(:pre_create) || hooks.include?(:post_delete)
|
243
|
+
end
|
171
244
|
end
|
172
245
|
end
|
173
246
|
end
|
@@ -20,92 +20,98 @@
|
|
20
20
|
# c.parameter_sources['KMSKey1'] = Moonshot::AlwaysUseDefaultSource.new
|
21
21
|
# end
|
22
22
|
module Moonshot
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
module Plugins
|
24
|
+
class EncryptedParameters
|
25
|
+
# @param [String] kms_key_parameter_name
|
26
|
+
# The parameter name to store the KMS Key ARN as.
|
27
|
+
# @param [Array<String>] parameters
|
28
|
+
# Names of parameters to encrypt, if they are not already set.
|
29
|
+
def initialize(kms_key_parameter_name, parameters)
|
30
|
+
@kms_key_parameter_name = kms_key_parameter_name
|
31
|
+
@parameters = parameters
|
32
|
+
@delete_key = true
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
35
|
+
def pre_create(res)
|
36
|
+
@ilog = res.ilog
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
key_arn = find_or_create_kms_key
|
39
|
+
pe = ParameterEncrypter.new(key_arn)
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
@parameters.each do |parameter_name|
|
42
|
+
sp = Moonshot.config.parameters[parameter_name]
|
43
|
+
raise "No such parameter #{parameter_name}" unless sp
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
45
|
+
@ilog.start_threaded "Handling encrypted parameter #{parameter_name.blue}..." do |s|
|
46
|
+
if sp.use_previous?
|
47
|
+
# TODO: Remove this and the one below when the upstream race is fixed.
|
48
|
+
# See https://github.com/askreet/interactive-logger/issues/7
|
49
|
+
sleep 0.05
|
50
|
+
s.success "Using previous encrypted value for #{parameter_name.blue}."
|
51
|
+
elsif !sp.set? && !sp.default?
|
52
|
+
# If the parameter isn't set, we can't encrypt it. Doing
|
53
|
+
# nothing means we will give the user a friendly error message
|
54
|
+
# about unset parameters when the controller resumes.
|
55
|
+
sleep 0.05
|
56
|
+
s.failure "No value to encrypt for #{parameter_name.blue}!"
|
57
|
+
else
|
58
|
+
s.continue "Encrypting new value for parameter #{parameter_name.blue}..."
|
59
|
+
Moonshot.config.parameters[sp.name].set(pe.encrypt(sp.value))
|
60
|
+
s.success "Encrypted new value for parameter #{parameter_name.blue}!"
|
61
|
+
end
|
60
62
|
end
|
61
63
|
end
|
62
64
|
end
|
63
|
-
|
64
|
-
alias pre_update pre_create
|
65
|
+
alias pre_update pre_create
|
65
66
|
|
66
|
-
|
67
|
-
|
67
|
+
def post_delete(res)
|
68
|
+
key_arn = Moonshot.config.parameters[@kms_key_parameter_name].value
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
70
|
+
res.ilog.start_threaded "Cleaning up KMS Key #{@kms_key_parameter_name.blue}..." do |s|
|
71
|
+
if @delete_key
|
72
|
+
KmsKey.new(key_arn).delete
|
73
|
+
s.success "Deleted KMS Key #{@kms_key_parameter_name.blue}!"
|
74
|
+
else
|
75
|
+
# TODO: See above.
|
76
|
+
sleep 0.05
|
77
|
+
s.success "Retained KMS Key #{@kms_key_parameter_name.blue}."
|
78
|
+
end
|
77
79
|
end
|
78
80
|
end
|
79
|
-
end
|
80
81
|
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
def delete_cli_hook(parser)
|
83
|
+
parser.on(
|
84
|
+
'--retain-kms-key',
|
85
|
+
TrueClass,
|
86
|
+
'Do not delete the KMS Key for this environment.'
|
87
|
+
) do
|
88
|
+
@delete_key = false
|
89
|
+
end
|
84
90
|
end
|
85
|
-
end
|
86
91
|
|
87
|
-
|
92
|
+
private
|
88
93
|
|
89
|
-
|
90
|
-
|
94
|
+
def find_or_create_kms_key
|
95
|
+
key_arn = nil
|
91
96
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
97
|
+
@ilog.start_threaded "Checking for KMS Key #{@kms_key_parameter_name}" do |s|
|
98
|
+
if Moonshot.config.parameters.key?(@kms_key_parameter_name)
|
99
|
+
if 'Auto' == Moonshot.config.parameters[@kms_key_parameter_name].value
|
100
|
+
s.continue "Auto-generating KMS Key for #{@kms_key_parameter_name.blue}... "
|
101
|
+
key_arn = KmsKey.create.arn
|
102
|
+
Moonshot.config.parameters[@kms_key_parameter_name].set(key_arn)
|
103
|
+
s.success "Created a new KMS Key for #{@kms_key_parameter_name.blue}!"
|
104
|
+
else
|
105
|
+
key_arn = KmsKey.new(Moonshot.config.parameters[@kms_key_parameter_name].value).arn
|
106
|
+
s.success "Using existing KMS Key for #{@kms_key_parameter_name.blue}!"
|
107
|
+
end
|
102
108
|
end
|
103
109
|
end
|
104
|
-
end
|
105
110
|
|
106
|
-
|
111
|
+
raise "No such Stack Parameter #{@kms_key_parameter_name}!" unless key_arn
|
107
112
|
|
108
|
-
|
113
|
+
key_arn
|
114
|
+
end
|
109
115
|
end
|
110
116
|
end
|
111
117
|
end
|
@@ -1,23 +1,25 @@
|
|
1
1
|
module Moonshot
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
module Plugins
|
3
|
+
class EncryptedParameters
|
4
|
+
# Class that manages KMS keys in AWS.
|
5
|
+
class KmsKey
|
6
|
+
attr_reader :arn
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
def initialize(arn)
|
9
|
+
@arn = arn
|
10
|
+
@kms_client = Aws::KMS::Client.new
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def self.create
|
14
|
+
resp = Aws::KMS::Client.new.create_key
|
15
|
+
arn = resp.key_metadata.arn
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
new(arn)
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
def delete
|
21
|
+
@kms_client.schedule_key_deletion(key_id: @arn, pending_window_in_days: 7)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -1,23 +1,25 @@
|
|
1
1
|
require 'base64'
|
2
2
|
module Moonshot
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
module Plugins
|
4
|
+
class EncryptedParameters
|
5
|
+
# Class that can encrypt and decrypt parameters using KMS.
|
6
|
+
class ParameterEncrypter
|
7
|
+
# @param [String] key_arn The ARN for the KMS key.
|
8
|
+
def initialize(key_arn)
|
9
|
+
@kms_client = Aws::KMS::Client.new
|
10
|
+
@key_arn = key_arn
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
# Encrypt and base64 encode the parameter value.
|
14
|
+
#
|
15
|
+
# @param [String] param_value The parameter to encrypt.
|
16
|
+
# @return [String] base64 encoded encrypted ciphertext.
|
17
|
+
def encrypt(param_value)
|
18
|
+
resp = @kms_client.encrypt(key_id: @key_arn, plaintext: param_value)
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
# Use strict here to avoid newlines which cause issues with parameters.
|
21
|
+
Base64.strict_encode64(resp.ciphertext_blob)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
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:
|
4
|
+
version: 2.0.0.beta1
|
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-02-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|