stacker 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/stacker/cli.rb +24 -9
- data/lib/stacker/stack.rb +59 -7
- data/lib/stacker/version.rb +1 -1
- metadata +20 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2fc55049bd623960704c1fd41806d7cd649e32b7
|
4
|
+
data.tar.gz: a1251cd848cd6fc8e24ed819df0c113e9997757b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bba3693278a33e76d4dba9ffd54e3e355fc01c72a8430aaec6566c38c5570c612b21eccfa537d302d0b5224c84f7e4e5c293c892c71dbc72500593a442ce1c76
|
7
|
+
data.tar.gz: fd29533ef84783f7e303f118ecf15e5dcea095ac0098490c3fd629833dd5db2dd4af9f87fc87e8039ce5840b931167c3cd523f75154f263346d96675873332be
|
data/lib/stacker/cli.rb
CHANGED
@@ -10,8 +10,15 @@ module Stacker
|
|
10
10
|
default_path = ENV['STACKER_PATH'] || '.'
|
11
11
|
default_region = ENV['STACKER_REGION'] || 'us-east-1'
|
12
12
|
|
13
|
-
method_option :path,
|
14
|
-
|
13
|
+
method_option :path, type: :string, default: default_path,
|
14
|
+
banner: 'project path'
|
15
|
+
|
16
|
+
method_option :region, type: :string, default: default_region,
|
17
|
+
banner: 'AWS region name'
|
18
|
+
|
19
|
+
method_option :allow_destructive, type: :boolean, default: false,
|
20
|
+
banner: 'allow destructive updates'
|
21
|
+
|
15
22
|
def initialize(*args); super(*args) end
|
16
23
|
|
17
24
|
desc "init [PATH]", "Create stacker project directories"
|
@@ -63,9 +70,9 @@ module Stacker
|
|
63
70
|
|
64
71
|
if yes? "Update remote template with these changes (y/n)?"
|
65
72
|
time = Benchmark.realtime do
|
66
|
-
stack.update
|
73
|
+
stack.update allow_destructive: options['allow_destructive']
|
67
74
|
end
|
68
|
-
Stacker.logger.info
|
75
|
+
Stacker.logger.info formatted_time stack_name, 'updated', time
|
69
76
|
else
|
70
77
|
Stacker.logger.warn 'Update skipped'
|
71
78
|
end
|
@@ -74,7 +81,7 @@ module Stacker
|
|
74
81
|
time = Benchmark.realtime do
|
75
82
|
stack.create
|
76
83
|
end
|
77
|
-
Stacker.logger.info
|
84
|
+
Stacker.logger.info formatted_time stack_name, 'created', time
|
78
85
|
else
|
79
86
|
Stacker.logger.warn 'Create skipped'
|
80
87
|
end
|
@@ -139,6 +146,10 @@ YAML
|
|
139
146
|
end
|
140
147
|
end
|
141
148
|
|
149
|
+
def formatted_time stack, action, benchmark
|
150
|
+
"Stack #{stack} #{action} in: #{(benchmark / 60).floor} min and #{(benchmark % 60).round} seconds."
|
151
|
+
end
|
152
|
+
|
142
153
|
def full_diff stack
|
143
154
|
templ_diff = stack.template.diff :color
|
144
155
|
param_diff = stack.parameters.diff :color
|
@@ -182,10 +193,6 @@ YAML
|
|
182
193
|
stack.parameters.resolved
|
183
194
|
end
|
184
195
|
|
185
|
-
def time (stack, action, benchmark)
|
186
|
-
return "Stack #{stack} #{action} in: #{(benchmark / 60).floor} min and #{(benchmark % 60).round} seconds."
|
187
|
-
end
|
188
|
-
|
189
196
|
def with_one_or_all stack_name = nil, &block
|
190
197
|
yield_with_stack = proc do |stack|
|
191
198
|
Stacker.logger.info "#{stack.name}:"
|
@@ -199,6 +206,14 @@ YAML
|
|
199
206
|
region.stacks.each(&yield_with_stack)
|
200
207
|
end
|
201
208
|
|
209
|
+
rescue Stacker::Stack::StackPolicyError => err
|
210
|
+
if options['allow_destructive']
|
211
|
+
Stacker.logger.fatal err.message
|
212
|
+
else
|
213
|
+
Stacker.logger.fatal 'Stack update policy prevents replacing or destroying resources.'
|
214
|
+
Stacker.logger.warn 'Try running again with \'--allow-destructive\''
|
215
|
+
end
|
216
|
+
exit 1
|
202
217
|
rescue Stacker::Stack::Error => err
|
203
218
|
Stacker.logger.fatal err.message
|
204
219
|
exit 1
|
data/lib/stacker/stack.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
1
2
|
require 'active_support/core_ext/hash/slice'
|
2
3
|
require 'active_support/core_ext/module/delegation'
|
3
4
|
require 'aws-sdk'
|
@@ -9,10 +10,11 @@ require 'stacker/stack/template'
|
|
9
10
|
module Stacker
|
10
11
|
class Stack
|
11
12
|
|
12
|
-
class Error < StandardError;
|
13
|
+
class Error < StandardError; end
|
14
|
+
class StackPolicyError < Error; end
|
13
15
|
class DoesNotExistError < Error; end
|
14
16
|
class MissingParameters < Error; end
|
15
|
-
class UpToDateError < Error;
|
17
|
+
class UpToDateError < Error; end
|
16
18
|
|
17
19
|
extend Memoist
|
18
20
|
|
@@ -25,6 +27,25 @@ module Stacker
|
|
25
27
|
status_reason
|
26
28
|
]
|
27
29
|
|
30
|
+
SAFE_UPDATE_POLICY = <<-JSON
|
31
|
+
{
|
32
|
+
"Statement" : [
|
33
|
+
{
|
34
|
+
"Effect" : "Deny",
|
35
|
+
"Action" : ["Update:Replace", "Update:Delete"],
|
36
|
+
"Principal" : "*",
|
37
|
+
"Resource" : "*"
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"Effect" : "Allow",
|
41
|
+
"Action" : "Update:*",
|
42
|
+
"Principal" : "*",
|
43
|
+
"Resource" : "*"
|
44
|
+
}
|
45
|
+
]
|
46
|
+
}
|
47
|
+
JSON
|
48
|
+
|
28
49
|
attr_reader :region, :name, :options
|
29
50
|
|
30
51
|
def initialize region, name, options = {}
|
@@ -87,7 +108,12 @@ module Stacker
|
|
87
108
|
raise Error.new err.message
|
88
109
|
end
|
89
110
|
|
90
|
-
def update
|
111
|
+
def update options = {}
|
112
|
+
options.assert_valid_keys(:blocking, :allow_destructive)
|
113
|
+
|
114
|
+
blocking = options.fetch(:blocking, true)
|
115
|
+
allow_destructive = options.fetch(:allow_destructive, false)
|
116
|
+
|
91
117
|
if parameters.missing.any?
|
92
118
|
raise MissingParameters.new(
|
93
119
|
"Required parameters missing: #{parameters.missing.join ', '}"
|
@@ -96,11 +122,17 @@ module Stacker
|
|
96
122
|
|
97
123
|
Stacker.logger.info 'Updating stack'
|
98
124
|
|
99
|
-
|
125
|
+
update_params = {
|
100
126
|
template: template.local,
|
101
127
|
parameters: parameters.resolved,
|
102
128
|
capabilities: capabilities.local
|
103
|
-
|
129
|
+
}
|
130
|
+
|
131
|
+
unless allow_destructive
|
132
|
+
update_params[:stack_policy_during_update_body] = SAFE_UPDATE_POLICY
|
133
|
+
end
|
134
|
+
|
135
|
+
client.update(update_params)
|
104
136
|
|
105
137
|
wait_while_status 'UPDATE_IN_PROGRESS' if blocking
|
106
138
|
rescue AWS::CloudFormation::Errors::ValidationError => err
|
@@ -116,12 +148,32 @@ module Stacker
|
|
116
148
|
|
117
149
|
private
|
118
150
|
|
151
|
+
def report_status
|
152
|
+
case status
|
153
|
+
when /_COMPLETE$/
|
154
|
+
Stacker.logger.info "#{name} Status => #{status}"
|
155
|
+
when /_ROLLBACK_IN_PROGRESS$/
|
156
|
+
failure_event = client.events.enum(limit: 30).find do |event|
|
157
|
+
event.resource_status =~ /_FAILED$/
|
158
|
+
end
|
159
|
+
failure_reason = failure_event.resource_status_reason
|
160
|
+
if failure_reason =~ /stack policy/
|
161
|
+
raise StackPolicyError.new failure_reason
|
162
|
+
else
|
163
|
+
Stacker.logger.fatal "#{name} Status => #{status}"
|
164
|
+
raise Error.new "Failure Reason: #{failure_reason}"
|
165
|
+
end
|
166
|
+
else
|
167
|
+
Stacker.logger.debug "#{name} Status => #{status}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
119
171
|
def wait_while_status wait_status
|
120
172
|
while flush_cache(:status) && status == wait_status
|
121
|
-
|
173
|
+
report_status
|
122
174
|
sleep 5
|
123
175
|
end
|
124
|
-
|
176
|
+
report_status
|
125
177
|
end
|
126
178
|
|
127
179
|
end
|
data/lib/stacker/version.rb
CHANGED
metadata
CHANGED
@@ -1,125 +1,125 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stacker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cotap, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '4.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: aws-sdk
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: coderay
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.1'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: diffy
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '3.0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: indentation
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - ~>
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0.0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - ~>
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: memoist
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0.9'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0.9'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rainbow
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - ~>
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '1.1'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - ~>
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1.1'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: thor
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - ~>
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '0.18'
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - ~>
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0.18'
|
125
125
|
- !ruby/object:Gem::Dependency
|
@@ -182,12 +182,12 @@ require_paths:
|
|
182
182
|
- lib
|
183
183
|
required_ruby_version: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- -
|
185
|
+
- - ">="
|
186
186
|
- !ruby/object:Gem::Version
|
187
187
|
version: 1.9.3
|
188
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
189
|
requirements:
|
190
|
-
- -
|
190
|
+
- - ">="
|
191
191
|
- !ruby/object:Gem::Version
|
192
192
|
version: '0'
|
193
193
|
requirements: []
|