cuffsert 0.10.1 → 0.11.0
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/Gemfile.lock +16 -6
- data/cuffsert.gemspec +2 -1
- data/lib/cuffsert/actions.rb +109 -0
- data/lib/cuffsert/cfarguments.rb +41 -10
- data/lib/cuffsert/cli_args.rb +11 -0
- data/lib/cuffsert/main.rb +21 -69
- data/lib/cuffsert/messages.rb +10 -2
- data/lib/cuffsert/metadata.rb +5 -1
- data/lib/cuffsert/presenters.rb +16 -8
- data/lib/cuffsert/rxcfclient.rb +11 -10
- data/lib/cuffsert/rxs3client.rb +44 -0
- data/lib/cuffsert/version.rb +1 -1
- metadata +20 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1be8dd08dce49cf000289c1a1e198026bf48e2c5
|
4
|
+
data.tar.gz: 3e0846cd94c5273d1ef260105b962c3c3196d6cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75340fd814849e4c1f42f6ec007eac89d20d2f925b599cdaf9ad32e489638ac00808a9879e2361f8c5d5833a2082b3b0f3992f90e2c061d8efa0f3e7ad6e4e3a
|
7
|
+
data.tar.gz: 92da57f24fb3c7443462404602d22b9a28c615ecd258e648e4bf22640e3441224e48465266f766ffc930b0a639a885e2ba674de7109e602e457d647431c150fa
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cuffsert (0.
|
4
|
+
cuffsert (0.11.0)
|
5
5
|
aws-sdk-cloudformation (~> 1.3.0)
|
6
|
+
aws-sdk-s3 (~> 1.8.0)
|
6
7
|
colorize
|
7
8
|
ruby-termios
|
8
9
|
rx
|
@@ -10,20 +11,29 @@ PATH
|
|
10
11
|
GEM
|
11
12
|
remote: https://rubygems.org/
|
12
13
|
specs:
|
13
|
-
aws-
|
14
|
+
aws-eventstream (1.0.0)
|
15
|
+
aws-partitions (1.87.0)
|
14
16
|
aws-sdk-cloudformation (1.3.0)
|
15
17
|
aws-sdk-core (~> 3)
|
16
18
|
aws-sigv4 (~> 1.0)
|
17
|
-
aws-sdk-core (3.
|
19
|
+
aws-sdk-core (3.21.2)
|
20
|
+
aws-eventstream (~> 1.0)
|
18
21
|
aws-partitions (~> 1.0)
|
19
22
|
aws-sigv4 (~> 1.0)
|
20
23
|
jmespath (~> 1.0)
|
24
|
+
aws-sdk-kms (1.5.0)
|
25
|
+
aws-sdk-core (~> 3)
|
26
|
+
aws-sigv4 (~> 1.0)
|
27
|
+
aws-sdk-s3 (1.8.2)
|
28
|
+
aws-sdk-core (~> 3)
|
29
|
+
aws-sdk-kms (~> 1)
|
30
|
+
aws-sigv4 (~> 1.0)
|
21
31
|
aws-sigv4 (1.0.2)
|
22
32
|
byebug (9.0.6)
|
23
33
|
colorize (0.8.1)
|
24
34
|
diff-lcs (1.2.5)
|
25
35
|
docile (1.1.5)
|
26
|
-
jmespath (1.
|
36
|
+
jmespath (1.4.0)
|
27
37
|
json (2.0.2)
|
28
38
|
rspec (3.5.0)
|
29
39
|
rspec-core (~> 3.5.0)
|
@@ -40,7 +50,7 @@ GEM
|
|
40
50
|
rspec-support (3.5.0)
|
41
51
|
ruby-termios (1.0.2)
|
42
52
|
rx (0.0.3)
|
43
|
-
rx-rspec (0.
|
53
|
+
rx-rspec (0.4.3)
|
44
54
|
rx
|
45
55
|
simplecov (0.12.0)
|
46
56
|
docile (~> 1.1.0)
|
@@ -56,7 +66,7 @@ DEPENDENCIES
|
|
56
66
|
byebug
|
57
67
|
cuffsert!
|
58
68
|
rspec (~> 3.0)
|
59
|
-
rx-rspec (~> 0.
|
69
|
+
rx-rspec (~> 0.4.3)
|
60
70
|
simplecov
|
61
71
|
|
62
72
|
BUNDLED WITH
|
data/cuffsert.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.required_ruby_version = '>= 2.0.0'
|
17
17
|
|
18
18
|
spec.add_runtime_dependency 'aws-sdk-cloudformation', '~> 1.3.0'
|
19
|
+
spec.add_runtime_dependency 'aws-sdk-s3', '~> 1.8.0'
|
19
20
|
spec.add_runtime_dependency 'colorize'
|
20
21
|
spec.add_runtime_dependency 'ruby-termios'
|
21
22
|
spec.add_runtime_dependency 'rx'
|
@@ -23,6 +24,6 @@ Gem::Specification.new do |spec|
|
|
23
24
|
spec.add_development_dependency 'bundler', '~> 1.12'
|
24
25
|
spec.add_development_dependency 'byebug'
|
25
26
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
-
spec.add_development_dependency 'rx-rspec', '~> 0.
|
27
|
+
spec.add_development_dependency 'rx-rspec', '~> 0.4.3'
|
27
28
|
spec.add_development_dependency 'simplecov'
|
28
29
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'cuffsert/actions'
|
2
|
+
require 'cuffsert/cfarguments'
|
3
|
+
require 'cuffsert/messages'
|
4
|
+
require 'rx'
|
5
|
+
|
6
|
+
module CuffSert
|
7
|
+
class BaseAction
|
8
|
+
attr_accessor :cfclient, :confirmation, :s3client
|
9
|
+
|
10
|
+
def initialize(meta, stack)
|
11
|
+
@cfclient = nil
|
12
|
+
@confirmation = nil
|
13
|
+
@meta = meta
|
14
|
+
@s3client = nil
|
15
|
+
@stack = stack
|
16
|
+
end
|
17
|
+
|
18
|
+
def upload_template_if_oversized(cfargs)
|
19
|
+
if cfargs[:template_body].nil? && cfargs[:template_url].nil?
|
20
|
+
raise 'Template bigger than 51200; please supply --s3-upload-prefix' unless @s3client
|
21
|
+
uri, progress = @s3client.upload(@meta.stack_uri)
|
22
|
+
[CuffSert.s3_uri_to_https(uri).to_s, progress]
|
23
|
+
else
|
24
|
+
[nil, Rx::Observable.empty]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class CreateStackAction < BaseAction
|
30
|
+
def as_observable
|
31
|
+
cfargs = CuffSert.as_create_stack_args(@meta)
|
32
|
+
upload_uri, maybe_upload = upload_template_if_oversized(cfargs)
|
33
|
+
cfargs[:template_url] = upload_uri if upload_uri
|
34
|
+
maybe_upload.concat(
|
35
|
+
Rx::Observable.of([:create, @meta.stackname]),
|
36
|
+
Rx::Observable.defer do
|
37
|
+
if @confirmation.call(@meta, :create, nil)
|
38
|
+
Rx::Observable.concat(
|
39
|
+
@cfclient.create_stack(cfargs),
|
40
|
+
Done.new.as_observable
|
41
|
+
)
|
42
|
+
else
|
43
|
+
Abort.new('User abort!').as_observable
|
44
|
+
end
|
45
|
+
end
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class UpdateStackAction < BaseAction
|
51
|
+
def as_observable
|
52
|
+
cfargs = CuffSert.as_update_change_set(@meta)
|
53
|
+
upload_uri, maybe_upload = upload_template_if_oversized(cfargs)
|
54
|
+
cfargs[:template_url] = upload_uri if upload_uri
|
55
|
+
maybe_upload
|
56
|
+
.concat(@cfclient.prepare_update(cfargs))
|
57
|
+
.flat_map do |change_set|
|
58
|
+
if change_set.is_a? Aws::CloudFormation::Types::DescribeChangeSetOutput
|
59
|
+
Rx::Observable.concat(
|
60
|
+
Rx::Observable.of(change_set),
|
61
|
+
Rx::Observable.defer {
|
62
|
+
if change_set[:status] == 'FAILED'
|
63
|
+
Rx::Observable.concat(
|
64
|
+
@cfclient.abort_update(change_set[:change_set_id]),
|
65
|
+
Abort.new("Update failed: #{change_set[:status_reason]}").as_observable
|
66
|
+
)
|
67
|
+
elsif @confirmation.call(@meta, :update, change_set)
|
68
|
+
Rx::Observable.concat(
|
69
|
+
@cfclient.update_stack(change_set[:stack_id], change_set[:change_set_id]),
|
70
|
+
Done.new.as_observable
|
71
|
+
)
|
72
|
+
else
|
73
|
+
Rx::Observable.concat(
|
74
|
+
@cfclient.abort_update(change_set[:change_set_id]),
|
75
|
+
Abort.new('User abort!').as_observable
|
76
|
+
)
|
77
|
+
end
|
78
|
+
}
|
79
|
+
)
|
80
|
+
else
|
81
|
+
Rx::Observable.just(change_set)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class RecreateStackAction < BaseAction
|
88
|
+
def as_observable
|
89
|
+
crt_args = CuffSert.as_create_stack_args(@meta)
|
90
|
+
del_args = CuffSert.as_delete_stack_args(@stack)
|
91
|
+
upload_uri, maybe_upload = upload_template_if_oversized(crt_args)
|
92
|
+
crt_args[:template_url] = upload_uri if upload_uri
|
93
|
+
maybe_upload.concat(
|
94
|
+
Rx::Observable.of([:recreate, @stack]),
|
95
|
+
Rx::Observable.defer do
|
96
|
+
if @confirmation.call(@meta, :recreate, @stack)
|
97
|
+
Rx::Observable.concat(
|
98
|
+
@cfclient.delete_stack(del_args),
|
99
|
+
@cfclient.create_stack(crt_args),
|
100
|
+
Done.new.as_observable
|
101
|
+
)
|
102
|
+
else
|
103
|
+
CuffSert::Abort.new('User abort!').as_observable
|
104
|
+
end
|
105
|
+
end
|
106
|
+
)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/cuffsert/cfarguments.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'open-uri'
|
2
|
+
require 'yaml'
|
2
3
|
|
3
4
|
# TODO:
|
4
5
|
# - propagate timeout here (from config?)
|
5
|
-
# - fail on template body > 51200 bytes
|
6
6
|
# - creation change-set: cfargs[:change_set_type] = 'CREATE'
|
7
7
|
|
8
8
|
module CuffSert
|
@@ -33,15 +33,7 @@ module CuffSert
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
cfargs[:template_url] = meta.stack_uri.to_s
|
38
|
-
elsif meta.stack_uri.scheme == 'file'
|
39
|
-
file = meta.stack_uri.to_s.sub(/^file:\/+/, '/')
|
40
|
-
cfargs[:template_body] = open(file).read
|
41
|
-
else
|
42
|
-
raise "Unsupported scheme #{meta.stack_uri.scheme}"
|
43
|
-
end
|
44
|
-
cfargs
|
36
|
+
cfargs.merge!(self.template_parameters(meta))
|
45
37
|
end
|
46
38
|
|
47
39
|
def self.as_create_stack_args(meta)
|
@@ -65,4 +57,43 @@ module CuffSert
|
|
65
57
|
def self.as_delete_stack_args(stack)
|
66
58
|
{ :stack_name => stack[:stack_id] }
|
67
59
|
end
|
60
|
+
|
61
|
+
def self.s3_uri_to_https(uri)
|
62
|
+
region = ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION'] || 'us-east-1'
|
63
|
+
bucket = uri.host
|
64
|
+
key = uri.path
|
65
|
+
host = region == 'us-east-1' ? 's3.amazonaws.com' : "s3-#{region}.amazonaws.com"
|
66
|
+
"https://#{host}/#{bucket}#{key}"
|
67
|
+
end
|
68
|
+
|
69
|
+
private_class_method
|
70
|
+
|
71
|
+
def self.load_minified_template(file)
|
72
|
+
template = open(file).read
|
73
|
+
YAML.load(template).to_json
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.template_parameters(meta)
|
77
|
+
template_parameters = {}
|
78
|
+
|
79
|
+
if meta.stack_uri.scheme == 's3'
|
80
|
+
template_parameters[:template_url] = self.s3_uri_to_https(meta.stack_uri)
|
81
|
+
elsif meta.stack_uri.scheme == 'https'
|
82
|
+
if meta.stack_uri.host.end_with?('amazonaws.com')
|
83
|
+
template_parameters[:template_url] = meta.stack_uri.to_s
|
84
|
+
else
|
85
|
+
raise 'Only HTTPS URLs pointing to amazonaws.com supported.'
|
86
|
+
end
|
87
|
+
elsif meta.stack_uri.scheme == 'file'
|
88
|
+
file = meta.stack_uri.to_s.sub(/^file:\/+/, '/')
|
89
|
+
template = self.load_minified_template(file)
|
90
|
+
if template.size <= 51200
|
91
|
+
template_parameters[:template_body] = template
|
92
|
+
end
|
93
|
+
else
|
94
|
+
raise "Unsupported scheme #{meta.stack_uri.scheme}"
|
95
|
+
end
|
96
|
+
|
97
|
+
template_parameters
|
98
|
+
end
|
68
99
|
end
|
data/lib/cuffsert/cli_args.rb
CHANGED
@@ -60,6 +60,17 @@ module CuffSert
|
|
60
60
|
args[:overrides][:tags][key] = val
|
61
61
|
end
|
62
62
|
|
63
|
+
opts.on('--region=aws_region', 'AWS region, overrides env variable AWS_REGION') do |region|
|
64
|
+
args[:aws_region] = region
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on('--s3-upload-prefix=prefix', 'Templates > 51200 bytes are uploaded here. Format: s3://bucket-name/[pre/fix]') do |prefix|
|
68
|
+
unless prefix.start_with?('s3://')
|
69
|
+
raise "Upload prefix #{prefix} must start with s3://"
|
70
|
+
end
|
71
|
+
args[:s3_upload_prefix] = prefix
|
72
|
+
end
|
73
|
+
|
63
74
|
opts.on('--json', 'Output events in JSON, no progressbar, colors') do
|
64
75
|
args[:output] = :json
|
65
76
|
end
|
data/lib/cuffsert/main.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'cuffsert/
|
1
|
+
require 'cuffsert/actions'
|
2
2
|
require 'cuffsert/cfstates'
|
3
3
|
require 'cuffsert/cli_args'
|
4
4
|
require 'cuffsert/confirmation'
|
@@ -6,79 +6,27 @@ require 'cuffsert/messages'
|
|
6
6
|
require 'cuffsert/metadata'
|
7
7
|
require 'cuffsert/presenters'
|
8
8
|
require 'cuffsert/rxcfclient'
|
9
|
+
require 'cuffsert/rxs3client'
|
9
10
|
require 'rx'
|
10
11
|
require 'uri'
|
11
12
|
|
12
13
|
module CuffSert
|
13
|
-
def self.
|
14
|
-
|
15
|
-
Rx::Observable.concat(
|
16
|
-
Rx::Observable.of([:create, meta.stackname]),
|
17
|
-
Rx::Observable.defer do
|
18
|
-
if confirm_create.call(meta, :create, nil)
|
19
|
-
client.create_stack(cfargs)
|
20
|
-
else
|
21
|
-
Abort.new('User abort!').as_observable
|
22
|
-
end
|
23
|
-
end
|
24
|
-
)
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.update_stack(client, meta, confirm_update)
|
28
|
-
cfargs = CuffSert.as_update_change_set(meta)
|
29
|
-
client.prepare_update(cfargs)
|
30
|
-
.last
|
31
|
-
.flat_map do |change_set|
|
32
|
-
Rx::Observable.concat(
|
33
|
-
Rx::Observable.of(change_set),
|
34
|
-
Rx::Observable.defer {
|
35
|
-
if change_set[:status] == 'FAILED'
|
36
|
-
client.abort_update(change_set[:change_set_id])
|
37
|
-
elsif confirm_update.call(meta, :update, change_set)
|
38
|
-
client.update_stack(change_set[:stack_id], change_set[:change_set_id])
|
39
|
-
else
|
40
|
-
Rx::Observable.concat(
|
41
|
-
client.abort_update(change_set[:change_set_id]),
|
42
|
-
Abort.new('User abort!').as_observable
|
43
|
-
)
|
44
|
-
end
|
45
|
-
}
|
46
|
-
)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.recreate_stack(client, stack, meta, confirm_recreate)
|
51
|
-
crt_args = CuffSert.as_create_stack_args(meta)
|
52
|
-
del_args = CuffSert.as_delete_stack_args(stack)
|
53
|
-
Rx::Observable.concat(
|
54
|
-
Rx::Observable.of([:recreate, stack]),
|
55
|
-
Rx::Observable.defer do
|
56
|
-
if confirm_recreate.call(meta, :recreate, stack)
|
57
|
-
Rx::Observable.concat(
|
58
|
-
client.delete_stack(del_args),
|
59
|
-
client.create_stack(crt_args)
|
60
|
-
)
|
61
|
-
else
|
62
|
-
CuffSert::Abort.new('User abort!').as_observable
|
63
|
-
end
|
64
|
-
end
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.execute(meta, confirm_update, force_replace: false, client: RxCFClient.new)
|
69
|
-
sources = []
|
70
|
-
found = client.find_stack_blocking(meta)
|
14
|
+
def self.determine_action(meta, cfclient, force_replace: false)
|
15
|
+
found = cfclient.find_stack_blocking(meta)
|
71
16
|
|
72
17
|
if found && INPROGRESS_STATES.include?(found[:stack_status])
|
73
|
-
|
74
|
-
elsif found.nil?
|
75
|
-
sources << self.create_stack(client, meta, confirm_update)
|
76
|
-
elsif found[:stack_status] == 'ROLLBACK_COMPLETE' || force_replace
|
77
|
-
sources << self.recreate_stack(client, found, meta, confirm_update)
|
18
|
+
action = Abort.new('Stack operation already in progress')
|
78
19
|
else
|
79
|
-
|
20
|
+
if found.nil?
|
21
|
+
action = CreateStackAction.new(meta, nil)
|
22
|
+
elsif found[:stack_status] == 'ROLLBACK_COMPLETE' || force_replace
|
23
|
+
action = RecreateStackAction.new(meta, found)
|
24
|
+
else
|
25
|
+
action = UpdateStackAction.new(meta, found)
|
26
|
+
end
|
27
|
+
yield action
|
80
28
|
end
|
81
|
-
|
29
|
+
action
|
82
30
|
end
|
83
31
|
|
84
32
|
def self.make_renderer(cli_args)
|
@@ -93,9 +41,13 @@ module CuffSert
|
|
93
41
|
cli_args = CuffSert.parse_cli_args(argv)
|
94
42
|
CuffSert.validate_cli_args(cli_args)
|
95
43
|
meta = CuffSert.build_meta(cli_args)
|
96
|
-
|
97
|
-
|
44
|
+
cfclient = RxCFClient.new(cli_args)
|
45
|
+
action = CuffSert.determine_action(meta, cfclient, force_replace: cli_args[:force_replace]) do |a|
|
46
|
+
a.confirmation = CuffSert.method(:confirmation)
|
47
|
+
a.s3client = RxS3Client.new(cli_args) if cli_args[:s3_upload_prefix]
|
48
|
+
a.cfclient = cfclient
|
49
|
+
end
|
98
50
|
renderer = CuffSert.make_renderer(cli_args)
|
99
|
-
RendererPresenter.new(
|
51
|
+
RendererPresenter.new(action.as_observable, renderer)
|
100
52
|
end
|
101
53
|
end
|
data/lib/cuffsert/messages.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module CuffSert
|
2
|
-
class
|
2
|
+
class Message
|
3
3
|
attr_reader :message
|
4
4
|
|
5
5
|
def initialize(message)
|
@@ -8,11 +8,19 @@ module CuffSert
|
|
8
8
|
|
9
9
|
def ===(other)
|
10
10
|
# For the benefit of value_matches? and regex
|
11
|
-
other.is_a?(
|
11
|
+
other.is_a?(self.class) && (other.message === @message || @message === other.message)
|
12
12
|
end
|
13
13
|
|
14
14
|
def as_observable
|
15
15
|
Rx::Observable.just(self)
|
16
16
|
end
|
17
17
|
end
|
18
|
+
|
19
|
+
class Abort < Message ; end
|
20
|
+
class Report < Message ; end
|
21
|
+
class Done < Message
|
22
|
+
def initialize
|
23
|
+
super('Done.')
|
24
|
+
end
|
25
|
+
end
|
18
26
|
end
|
data/lib/cuffsert/metadata.rb
CHANGED
@@ -82,7 +82,11 @@ module CuffSert
|
|
82
82
|
private_class_method
|
83
83
|
|
84
84
|
def self.meta_defaults(cli_args)
|
85
|
-
|
85
|
+
if File.exists?(cli_args[:stack_path][0])
|
86
|
+
nil_params = CuffBase.empty_from_template(open(cli_args[:stack_path][0]))
|
87
|
+
else
|
88
|
+
nil_params = {}
|
89
|
+
end
|
86
90
|
default = StackConfig.new
|
87
91
|
default.update_from({:parameters => nil_params})
|
88
92
|
default.suffix = File.basename(cli_args[:metadata], '.yml') if cli_args[:metadata]
|
data/lib/cuffsert/presenters.rb
CHANGED
@@ -5,7 +5,6 @@ require 'cuffsert/messages'
|
|
5
5
|
require 'rx'
|
6
6
|
|
7
7
|
# TODO: Animate in-progress states
|
8
|
-
# - Introduce a Done message and stop printing in on_complete
|
9
8
|
# - Present the error message in change_set properly - and abort
|
10
9
|
# - badness goes to stderr
|
11
10
|
# - change sets should present modification details indented under each entry
|
@@ -55,9 +54,6 @@ module CuffSert
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def on_event(event)
|
58
|
-
# Workaround for now
|
59
|
-
event = event.data if event.class == Seahorse::Client::Response
|
60
|
-
|
61
57
|
case event
|
62
58
|
when Aws::CloudFormation::Types::StackEvent
|
63
59
|
on_stack_event(event)
|
@@ -66,15 +62,18 @@ module CuffSert
|
|
66
62
|
# when [:recreate, Aws::CloudFormation::Types::Stack]
|
67
63
|
when Array
|
68
64
|
on_stack(*event)
|
65
|
+
when ::CuffSert::Report
|
66
|
+
@renderer.report(event)
|
69
67
|
when ::CuffSert::Abort
|
70
68
|
@renderer.abort(event)
|
69
|
+
when ::CuffSert::Done
|
70
|
+
@renderer.done(event)
|
71
71
|
else
|
72
72
|
puts event
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
def on_complete
|
77
|
-
@renderer.done
|
78
77
|
end
|
79
78
|
|
80
79
|
private
|
@@ -139,8 +138,9 @@ module CuffSert
|
|
139
138
|
def event(event, resource) ; end
|
140
139
|
def clear ; end
|
141
140
|
def resource(resource) ; end
|
141
|
+
def report(message) ; end
|
142
142
|
def abort(message) ; end
|
143
|
-
def done ; end
|
143
|
+
def done(event) ; end
|
144
144
|
end
|
145
145
|
|
146
146
|
class JsonRenderer < BaseRenderer
|
@@ -156,6 +156,10 @@ module CuffSert
|
|
156
156
|
@output.write(stack.to_json) unless @verbosity < 1
|
157
157
|
end
|
158
158
|
|
159
|
+
def report(event)
|
160
|
+
@output.write(event.message + "\n") unless @verbosity < 2
|
161
|
+
end
|
162
|
+
|
159
163
|
def abort(event)
|
160
164
|
@error.write(event.message + "\n") unless @verbosity < 1
|
161
165
|
end
|
@@ -279,12 +283,16 @@ module CuffSert
|
|
279
283
|
))
|
280
284
|
end
|
281
285
|
|
286
|
+
def report(event)
|
287
|
+
@output.write(event.message.colorize(:white) + "\n") unless @verbosity < 2
|
288
|
+
end
|
289
|
+
|
282
290
|
def abort(event)
|
283
291
|
@error.write(event.message.colorize(:red) + "\n") unless @verbosity < 1
|
284
292
|
end
|
285
293
|
|
286
|
-
def done
|
287
|
-
@output.write(
|
294
|
+
def done(event)
|
295
|
+
@output.write(event.message.colorize(:green) + "\n") unless @verbosity < 1
|
288
296
|
end
|
289
297
|
|
290
298
|
private
|
data/lib/cuffsert/rxcfclient.rb
CHANGED
@@ -4,13 +4,12 @@ require 'rx'
|
|
4
4
|
|
5
5
|
module CuffSert
|
6
6
|
class RxCFClient
|
7
|
-
def initialize(
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@pause = pause
|
7
|
+
def initialize(cli_args, **options)
|
8
|
+
initargs = {retry_limit: 8}
|
9
|
+
initargs[:region] = cli_args[:aws_region] if cli_args[:aws_region]
|
10
|
+
@cf = options[:aws_cf] || Aws::CloudFormation::Client.new(initargs)
|
11
|
+
@max_items = options[:max_items] || 1000
|
12
|
+
@pause = options[:pause] || 5
|
14
13
|
end
|
15
14
|
|
16
15
|
def find_stack_blocking(meta)
|
@@ -36,8 +35,10 @@ module CuffSert
|
|
36
35
|
change_set_id = @cf.create_change_set(cfargs)[:id]
|
37
36
|
loop do
|
38
37
|
change_set = @cf.describe_change_set(change_set_name: change_set_id)
|
39
|
-
|
40
|
-
|
38
|
+
if FINAL_STATES.include?(change_set.data[:status])
|
39
|
+
observer.on_next(change_set.data)
|
40
|
+
break
|
41
|
+
end
|
41
42
|
end
|
42
43
|
observer.on_completed
|
43
44
|
end
|
@@ -53,7 +54,7 @@ module CuffSert
|
|
53
54
|
observer.on_completed
|
54
55
|
end
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
def abort_update(change_set_id)
|
58
59
|
Rx::Observable.create do |observer|
|
59
60
|
@cf.delete_change_set(change_set_name: change_set_id)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'aws-sdk-s3'
|
2
|
+
require 'rx'
|
3
|
+
|
4
|
+
module CuffSert
|
5
|
+
class RxS3Client
|
6
|
+
def initialize(cli_args, client: nil)
|
7
|
+
@bucket, @path_prefix = split_prefix(cli_args[:s3_upload_prefix])
|
8
|
+
initargs = {retry_limit: 8}
|
9
|
+
initargs[:region] = cli_args[:aws_region] if cli_args[:aws_region]
|
10
|
+
@client = client || Aws::S3::Client.new(initargs)
|
11
|
+
end
|
12
|
+
|
13
|
+
def upload(stack_uri)
|
14
|
+
file = stack_uri.to_s.sub(/^file:\/+/, '/')
|
15
|
+
name = File.basename(file)
|
16
|
+
s3_uri = "s3://#{@bucket}/#{@path_prefix}#{name}"
|
17
|
+
observable = Rx::Observable.create do |observer|
|
18
|
+
body = open(file).read
|
19
|
+
begin
|
20
|
+
observer.on_next(Report.new("Uploading template to #{s3_uri}"))
|
21
|
+
@client.put_object({
|
22
|
+
body: body,
|
23
|
+
bucket: @bucket,
|
24
|
+
key: "#{@path_prefix}#{name}"
|
25
|
+
})
|
26
|
+
observer.on_completed
|
27
|
+
rescue => e
|
28
|
+
observer.on_error(e)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
[URI(s3_uri), observable]
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def split_prefix(s3_upload_prefix)
|
37
|
+
m = s3_upload_prefix.match(/^s3:\/\/([-a-z0-9]+)(\/?.*)$/)
|
38
|
+
bucket = m[1]
|
39
|
+
prefix = m[2].sub(/^\//, '')
|
40
|
+
prefix += '/' unless prefix.empty? || prefix.end_with?('/')
|
41
|
+
[bucket, prefix]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/cuffsert/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuffsert
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anders Qvist
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-cloudformation
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.3.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: aws-sdk-s3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.8.0
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: colorize
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +128,14 @@ dependencies:
|
|
114
128
|
requirements:
|
115
129
|
- - ~>
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.
|
131
|
+
version: 0.4.3
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
136
|
- - ~>
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
138
|
+
version: 0.4.3
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: simplecov
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,6 +173,7 @@ files:
|
|
159
173
|
- bin/cuffup
|
160
174
|
- cuffsert.gemspec
|
161
175
|
- lib/cuffbase.rb
|
176
|
+
- lib/cuffsert/actions.rb
|
162
177
|
- lib/cuffsert/cfarguments.rb
|
163
178
|
- lib/cuffsert/cfstates.rb
|
164
179
|
- lib/cuffsert/cli_args.rb
|
@@ -168,6 +183,7 @@ files:
|
|
168
183
|
- lib/cuffsert/metadata.rb
|
169
184
|
- lib/cuffsert/presenters.rb
|
170
185
|
- lib/cuffsert/rxcfclient.rb
|
186
|
+
- lib/cuffsert/rxs3client.rb
|
171
187
|
- lib/cuffsert/version.rb
|
172
188
|
- lib/cuffup.rb
|
173
189
|
homepage: https://github.com/bittrance/cuffsert
|