stackup 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f70a25b2393218900fde09713ec91cfc485121c2
4
- data.tar.gz: 3f6c5693a0b23ab0dd30884f7d42ed45e61ccc68
3
+ metadata.gz: cd8f6344aa29806003cac476d52ecd7070747ec3
4
+ data.tar.gz: 1a64e7205d279d0e7922171de005ac6ddcbb08ef
5
5
  SHA512:
6
- metadata.gz: 2e41add2eb41807de33893aa472613741925e420e9ee327c4bbab879bbb11d9e798fb09c022c0d0820da26f53b6a375564b62771156040bcd6d5da975a6ffb05
7
- data.tar.gz: 9131421f4beeca6244df73b7e9302587a6ca9c9e99c17aa8aa43497c3fca0270654bbb40de212807140a70bec462e1a6bc8fb2713933c9c3be164f052f9dc034
6
+ metadata.gz: abbf1538c8f0a04dcbd72b180803f7eb9211c07ec74eda51078135f40fd31088eaf6a3442688a6a92cee886799374475f7c4ca5ea9a350fc6fb6b6ea2ccc7b33
7
+ data.tar.gz: 6fd7cb6adb0b1bd846ab7a347be74f630a4ac6514db282d1f5cd3073991ce0155f80b09b100e32fbcd965f1ad30b6ab6d9caf9c7e0342756d6ee7b9c8a34dee8
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 1.1.0 (2017-02-23)
2
+
3
+ * The `stackup` CLI now allows stack template and policy documents to be specified as URLs.
4
+ * Template URL must point to a template stored in an Amazon S3 bucket, e.g. `https://s3-ap-southeast-2.amazonaws.com/bucket/template.json`.
5
+ * Policy URL must point to an object located in an S3 bucket in the same region as the stack.
6
+
1
7
  ## 1.0.4 (2017-01-04)
2
8
 
3
9
  * Fix #34: make YAML parsing work in ruby-2.0.
data/bin/stackup CHANGED
@@ -8,6 +8,7 @@ require "multi_json"
8
8
  require "securerandom"
9
9
  require "stackup"
10
10
  require "stackup/differ"
11
+ require "stackup/source"
11
12
  require "stackup/version"
12
13
  require "stackup/yaml"
13
14
 
@@ -55,6 +56,8 @@ Clamp do
55
56
 
56
57
  def run(arguments)
57
58
  super(arguments)
59
+ rescue Stackup::Source::ReadError => e
60
+ signal_error e.message
58
61
  rescue Stackup::ServiceError => e
59
62
  signal_error e.message
60
63
  rescue Aws::Errors::MissingCredentialsError
@@ -126,14 +129,10 @@ Clamp do
126
129
  puts final_status unless final_status.nil?
127
130
  end
128
131
 
129
- def load_data(file)
130
- Stackup::YAML.load_file(file)
131
- rescue Errno::ENOENT
132
- signal_error "no such file: #{file.inspect}"
133
- end
134
-
135
- def load_parameters(file)
136
- Stackup::Parameters.new(load_data(file)).to_hash
132
+ def parameters_from_files
133
+ parameter_sources.map { |src|
134
+ Stackup::Parameters.new(src.data).to_hash
135
+ }.inject(:merge)
137
136
  end
138
137
 
139
138
  subcommand "status", "Print stack status." do
@@ -144,42 +143,58 @@ Clamp do
144
143
 
145
144
  end
146
145
 
147
- subcommand "up", "Create/update the stack" do
146
+ subcommand "up", "Create/update the stack." do
148
147
 
149
- option ["-t", "--template"], "FILE", "template file",
150
- :attribute_name => :template_file
148
+ option ["-t", "--template"], "FILE", "template source",
149
+ :attribute_name => :template_source,
150
+ &Stackup::Source.method(:new)
151
151
 
152
152
  option ["-T", "--use-previous-template"], :flag,
153
153
  "reuse the existing template"
154
154
 
155
155
  option ["-p", "--parameters"], "FILE", "parameters file (last wins)",
156
156
  :multivalued => true,
157
- :attribute_name => :parameter_file_list
157
+ :attribute_name => :parameter_sources,
158
+ &Stackup::Source.method(:new)
158
159
 
159
160
  option ["-o", "--override"], "PARAM=VALUE", "parameter overrides",
160
161
  :multivalued => true,
161
162
  :attribute_name => :override_list
162
163
 
163
164
  option "--tags", "FILE", "stack tags file",
164
- :attribute_name => :tags_file
165
+ :attribute_name => :tag_source,
166
+ &Stackup::Source.method(:new)
165
167
 
166
168
  option "--policy", "FILE", "stack policy file",
167
- :attribute_name => :policy_file
169
+ :attribute_name => :policy_source,
170
+ &Stackup::Source.method(:new)
168
171
 
169
172
  option "--on-failure", "ACTION",
170
173
  "when stack creation fails: DO_NOTHING, ROLLBACK, or DELETE",
171
174
  :default => "ROLLBACK"
172
175
 
173
176
  def execute
174
- unless template_file || use_previous_template?
177
+ unless template_source || use_previous_template?
175
178
  signal_usage_error "Specify either --template or --use-previous-template"
176
179
  end
177
180
  options = {}
178
- options[:template] = load_data(template_file) if template_file
181
+ if template_source
182
+ if is_s3_url?(template_source.location)
183
+ options[:template_url] = template_source.location
184
+ else
185
+ options[:template] = template_source.data
186
+ end
187
+ end
179
188
  options[:on_failure] = on_failure
180
189
  options[:parameters] = parameters
181
- options[:tags] = load_data(tags_file) if tags_file
182
- options[:stack_policy] = load_data(policy_file) if policy_file
190
+ options[:tags] = tag_source.data if tag_source
191
+ if policy_source
192
+ if is_s3_url?(policy_source.location)
193
+ options[:stack_policy_url] = policy_source.location
194
+ else
195
+ options[:stack_policy] = policy_source.data
196
+ end
197
+ end
183
198
  options[:use_previous_template] = use_previous_template?
184
199
  report_change do
185
200
  stack.create_or_update(options)
@@ -189,9 +204,7 @@ Clamp do
189
204
  private
190
205
 
191
206
  def parameters
192
- hashes = parameter_file_list.map(&method(:load_parameters))
193
- hashes << parameter_overrides
194
- hashes.inject(:merge)
207
+ parameters_from_files.merge(parameter_overrides)
195
208
  end
196
209
 
197
210
  def parameter_overrides
@@ -203,36 +216,43 @@ Clamp do
203
216
  end
204
217
  end
205
218
 
219
+ def is_s3_url?(location)
220
+ location =~ %r{^https://s3\w*.amazonaws.com}
221
+ end
222
+
206
223
  end
207
224
 
208
225
  subcommand "diff", "Compare template/params to current stack." do
209
226
 
210
- option ["-t", "--template"], "FILE", "template file",
211
- :attribute_name => :template_file
227
+ option ["-t", "--template"], "FILE", "template source",
228
+ :attribute_name => :template_source,
229
+ &Stackup::Source.method(:new)
212
230
 
213
231
  option ["-p", "--parameters"], "FILE", "parameters file (last wins)",
214
232
  :multivalued => true,
215
- :attribute_name => :parameter_file_list
233
+ :attribute_name => :parameter_sources,
234
+ &Stackup::Source.method(:new)
216
235
 
217
236
  option "--tags", "FILE", "stack tags file",
218
- :attribute_name => :tags_file
237
+ :attribute_name => :tag_source,
238
+ &Stackup::Source.method(:new)
219
239
 
220
240
  option "--diff-format", "FORMAT", "'text', 'color', or 'html'", :default => "color"
221
241
 
222
242
  def execute
223
243
  current = {}
224
244
  planned = {}
225
- if template_file
245
+ if template_source
226
246
  current["Template"] = stack.template
227
- planned["Template"] = load_data(template_file)
247
+ planned["Template"] = template_source.data
228
248
  end
229
- unless parameter_file_list.empty?
249
+ unless parameter_sources.empty?
230
250
  current["Parameters"] = existing_parameters.sort.to_h
231
251
  planned["Parameters"] = new_parameters.sort.to_h
232
252
  end
233
- if tags_file
253
+ if tag_source
234
254
  current["Tags"] = stack.tags.sort.to_h
235
- planned["Tags"] = load_data(tags_file).sort.to_h
255
+ planned["Tags"] = tag_source.data.sort.to_h
236
256
  end
237
257
  signal_usage_error "specify '--template' or '--parameters'" if planned.empty?
238
258
  puts differ.diff(current, planned)
@@ -248,10 +268,6 @@ Clamp do
248
268
  @existing_parameters ||= stack.parameters
249
269
  end
250
270
 
251
- def parameters_from_files
252
- parameter_file_list.map(&method(:load_parameters)).inject(:merge)
253
- end
254
-
255
271
  def new_parameters
256
272
  existing_parameters.merge(parameters_from_files)
257
273
  end
@@ -268,7 +284,7 @@ Clamp do
268
284
 
269
285
  end
270
286
 
271
- subcommand "cancel-update", "Cancel the update in-progress" do
287
+ subcommand "cancel-update", "Cancel the update in-progress." do
272
288
 
273
289
  def execute
274
290
  report_change do
@@ -278,7 +294,7 @@ Clamp do
278
294
 
279
295
  end
280
296
 
281
- subcommand "wait", "Wait until stack is stable" do
297
+ subcommand "wait", "Wait until stack is stable." do
282
298
 
283
299
  def execute
284
300
  puts stack.wait
@@ -286,7 +302,7 @@ Clamp do
286
302
 
287
303
  end
288
304
 
289
- subcommand "events", "List stack events" do
305
+ subcommand "events", "List stack events." do
290
306
 
291
307
  option ["-f", "--follow"], :flag, "follow new events"
292
308
  option ["--data"], :flag, "display events as data"
@@ -376,7 +392,7 @@ Clamp do
376
392
 
377
393
  end
378
394
 
379
- subcommand "inspect", "Display stack particulars" do
395
+ subcommand "inspect", "Display stack particulars." do
380
396
 
381
397
  def execute
382
398
  data = {
@@ -0,0 +1,58 @@
1
+ require "aws-sdk-core"
2
+ require "open-uri"
3
+ require "stackup/stack"
4
+
5
+ module Stackup
6
+
7
+ # Represents a source of input, e.g. template, parameter, etc.
8
+ #
9
+ class Source
10
+
11
+ def initialize(location)
12
+ @location = location
13
+ end
14
+
15
+ attr_reader :location
16
+
17
+ def body
18
+ @body ||= read
19
+ end
20
+
21
+ def data
22
+ @data ||= parse_body
23
+ end
24
+
25
+ private
26
+
27
+ LOOKS_LIKE_JSON = /^\s*[\{\[]/
28
+
29
+ def uri
30
+ URI(location)
31
+ end
32
+
33
+ def read
34
+ if uri.scheme
35
+ uri.read
36
+ else
37
+ IO.read(location)
38
+ end
39
+ rescue Errno::ENOENT
40
+ raise ReadError, "no such file: #{location.inspect}"
41
+ rescue OpenURI::HTTPError => e
42
+ raise ReadError, "#{e}: #{location.inspect}"
43
+ end
44
+
45
+ def parse_body
46
+ if body =~ LOOKS_LIKE_JSON
47
+ MultiJson.load(body)
48
+ else
49
+ Stackup::YAML.load(body)
50
+ end
51
+ end
52
+
53
+ class ReadError < StandardError
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -1,5 +1,5 @@
1
1
  module Stackup
2
2
 
3
- VERSION = "1.0.4"
3
+ VERSION = "1.1.0"
4
4
 
5
5
  end
@@ -0,0 +1,75 @@
1
+ require "spec_helper"
2
+
3
+ require "multi_json"
4
+ require "stackup/source"
5
+ require "stackup/yaml"
6
+
7
+ describe Stackup::Source do
8
+
9
+ let(:example_dir) { File.expand_path("../../../examples", __FILE__) }
10
+
11
+ context "from a JSON file" do
12
+
13
+ let(:json_file) { File.join(example_dir, "template.json") }
14
+
15
+ subject(:source) { described_class.new(json_file) }
16
+
17
+ describe "#body" do
18
+
19
+ it "returns JSON body" do
20
+ expect(subject.body).to eql(File.read(json_file))
21
+ end
22
+
23
+ end
24
+
25
+ describe "#data" do
26
+
27
+ it "returns parsed JSON" do
28
+ expect(subject.data).to eql(MultiJson.load(File.read(json_file)))
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ context "from a YAML file" do
36
+
37
+ let(:yaml_file) { File.join(example_dir, "template.yml") }
38
+
39
+ subject(:source) { described_class.new(yaml_file) }
40
+
41
+ describe "#body" do
42
+
43
+ it "returns YAML body" do
44
+ expect(subject.body).to eql(File.read(yaml_file))
45
+ end
46
+
47
+ end
48
+
49
+ describe "#data" do
50
+
51
+ it "returns parsed YAML" do
52
+ expect(subject.data).to eql(Stackup::YAML.load_file(yaml_file))
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ context "with a non-existant file" do
60
+
61
+ let(:bogus_file) { "notreallythere.json" }
62
+
63
+ subject(:source) { described_class.new(bogus_file) }
64
+
65
+ describe "#body" do
66
+
67
+ it "raises a ReadError" do
68
+ expect { subject.body }.to raise_error(Stackup::Source::ReadError, %q(no such file: "notreallythere.json"))
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stackup
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Williams
@@ -9,76 +9,76 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-01-04 00:00:00.000000000 Z
12
+ date: 2017-02-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk-resources
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ~>
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
20
  version: '2.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ~>
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '2.0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: clamp
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ~>
32
+ - - "~>"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '1.0'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ~>
39
+ - - "~>"
40
40
  - !ruby/object:Gem::Version
41
41
  version: '1.0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: console_logger
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - '>='
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
48
  version: '0'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '>='
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: diffy
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - ~>
60
+ - - "~>"
61
61
  - !ruby/object:Gem::Version
62
62
  version: '3.0'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - ~>
67
+ - - "~>"
68
68
  - !ruby/object:Gem::Version
69
69
  version: '3.0'
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: multi_json
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - '>='
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - '>='
81
+ - - ">="
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
84
  description:
@@ -100,6 +100,7 @@ files:
100
100
  - lib/stackup/parameters.rb
101
101
  - lib/stackup/rake_tasks.rb
102
102
  - lib/stackup/service.rb
103
+ - lib/stackup/source.rb
103
104
  - lib/stackup/stack.rb
104
105
  - lib/stackup/stack_watcher.rb
105
106
  - lib/stackup/utils.rb
@@ -107,6 +108,7 @@ files:
107
108
  - lib/stackup/yaml.rb
108
109
  - spec/spec_helper.rb
109
110
  - spec/stackup/parameters_spec.rb
111
+ - spec/stackup/source_spec.rb
110
112
  - spec/stackup/stack_spec.rb
111
113
  - spec/stackup/stack_watcher_spec.rb
112
114
  - spec/stackup/utils_spec.rb
@@ -121,23 +123,24 @@ require_paths:
121
123
  - lib
122
124
  required_ruby_version: !ruby/object:Gem::Requirement
123
125
  requirements:
124
- - - '>='
126
+ - - ">="
125
127
  - !ruby/object:Gem::Version
126
128
  version: '0'
127
129
  required_rubygems_version: !ruby/object:Gem::Requirement
128
130
  requirements:
129
- - - '>='
131
+ - - ">="
130
132
  - !ruby/object:Gem::Version
131
133
  version: '0'
132
134
  requirements: []
133
135
  rubyforge_project:
134
- rubygems_version: 2.6.4
136
+ rubygems_version: 2.6.10
135
137
  signing_key:
136
138
  specification_version: 4
137
139
  summary: Manage CloudFormation stacks
138
140
  test_files:
139
141
  - spec/spec_helper.rb
140
142
  - spec/stackup/parameters_spec.rb
143
+ - spec/stackup/source_spec.rb
141
144
  - spec/stackup/stack_spec.rb
142
145
  - spec/stackup/stack_watcher_spec.rb
143
146
  - spec/stackup/utils_spec.rb