stack_master 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -0
  3. data/features/apply.feature +1 -1
  4. data/features/apply_with_s3.feature +106 -0
  5. data/features/step_definitions/stack_steps.rb +5 -0
  6. data/features/support/env.rb +1 -0
  7. data/lib/stack_master.rb +78 -58
  8. data/lib/stack_master/aws_driver/s3.rb +66 -0
  9. data/lib/stack_master/cli.rb +1 -0
  10. data/lib/stack_master/commands/apply.rb +52 -5
  11. data/lib/stack_master/commands/init.rb +2 -0
  12. data/lib/stack_master/commands/list_stacks.rb +2 -0
  13. data/lib/stack_master/commands/outputs.rb +2 -0
  14. data/lib/stack_master/commands/status.rb +3 -0
  15. data/lib/stack_master/parameter_resolver.rb +1 -1
  16. data/lib/stack_master/parameter_resolvers/secret.rb +2 -0
  17. data/lib/stack_master/stack.rb +20 -13
  18. data/lib/stack_master/stack_definition.rb +63 -13
  19. data/lib/stack_master/stack_differ.rb +2 -0
  20. data/lib/stack_master/stack_events/fetcher.rb +1 -1
  21. data/lib/stack_master/stack_events/presenter.rb +1 -1
  22. data/lib/stack_master/stack_events/streamer.rb +1 -1
  23. data/lib/stack_master/template_compiler.rb +3 -1
  24. data/lib/stack_master/template_compilers/cfndsl.rb +4 -2
  25. data/lib/stack_master/template_compilers/json.rb +4 -0
  26. data/lib/stack_master/template_compilers/sparkle_formation.rb +5 -0
  27. data/lib/stack_master/template_compilers/yaml.rb +4 -0
  28. data/lib/stack_master/test_driver/cloud_formation.rb +50 -36
  29. data/lib/stack_master/test_driver/s3.rb +34 -0
  30. data/lib/stack_master/testing.rb +1 -0
  31. data/lib/stack_master/utils.rb +19 -0
  32. data/lib/stack_master/version.rb +1 -1
  33. data/spec/fixtures/stack_master.yml +4 -1
  34. data/spec/stack_master/aws_driver/s3_spec.rb +130 -0
  35. data/spec/stack_master/commands/apply_spec.rb +26 -0
  36. data/spec/stack_master/config_spec.rb +8 -1
  37. data/spec/stack_master/parameter_resolver_spec.rb +5 -0
  38. data/spec/stack_master/sparkle_formation/user_data_file_spec.rb +2 -0
  39. data/spec/stack_master/stack_events/presenter_spec.rb +1 -1
  40. data/spec/stack_master/stack_spec.rb +23 -5
  41. data/spec/stack_master/template_compiler_spec.rb +1 -0
  42. data/spec/stack_master/template_compilers/cfndsl_spec.rb +2 -0
  43. data/spec/stack_master/test_driver/s3_spec.rb +17 -0
  44. data/stack_master.gemspec +0 -1
  45. metadata +10 -16
@@ -1,3 +1,3 @@
1
1
  module StackMaster
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -4,6 +4,9 @@ region_aliases:
4
4
  stack_defaults:
5
5
  tags:
6
6
  application: my-awesome-blog
7
+ s3:
8
+ bucket: my-bucket
9
+ region: us-east-1
7
10
  template_compilers:
8
11
  rb: ruby_dsl
9
12
  region_defaults:
@@ -37,4 +40,4 @@ stacks:
37
40
  myapp_web:
38
41
  template: myapp_web
39
42
  tags:
40
- test_override: 2
43
+ test_override: 2
@@ -0,0 +1,130 @@
1
+ RSpec.describe StackMaster::AwsDriver::S3 do
2
+ let(:region) { 'us-east-1' }
3
+ let(:bucket) { 'bucket' }
4
+ let(:s3) { Aws::S3::Client.new(stub_responses: true) }
5
+ subject(:s3_driver) { StackMaster::AwsDriver::S3.new }
6
+
7
+ before do
8
+ allow(Aws::S3::Client).to receive(:new).and_return(s3)
9
+ end
10
+
11
+ describe '#upload_files' do
12
+ before do
13
+ allow(File).to receive(:read).and_return('file content')
14
+ end
15
+
16
+ context 'when set_region is called' do
17
+ it 'defaults to that region' do
18
+ s3_driver.set_region('default')
19
+ expect(Aws::S3::Client).to receive(:new).with(region: 'default').and_return(s3)
20
+ files = {
21
+ 'template' => {
22
+ path: 'spec/fixtures/templates/myapp_vpc.json',
23
+ body: 'file content'
24
+ }
25
+ }
26
+ s3_driver.upload_files(bucket: 'b',
27
+ files: files)
28
+ end
29
+ end
30
+
31
+ context 'when called with a prefix' do
32
+ let(:options) do
33
+ {
34
+ bucket: 'bucket',
35
+ region: 'region',
36
+ prefix: 'prefix',
37
+ files: {'template' => {
38
+ path: 'spec/fixtures/templates/myapp_vpc.json',
39
+ body: 'file content'
40
+ }
41
+ }
42
+ }
43
+ end
44
+
45
+ it 'uploads files under a prefix' do
46
+ expect(s3).to receive(:put_object).with(bucket: 'bucket',
47
+ key: 'prefix/template',
48
+ body: 'file content',
49
+ metadata: {md5: "d10b4c3ff123b26dc068d43a8bef2d23"})
50
+ s3_driver.upload_files(options)
51
+ end
52
+ end
53
+
54
+ context 'when called without a prefix' do
55
+ let(:options) do
56
+ {
57
+ bucket: 'bucket',
58
+ region: 'region',
59
+ files: {'template' => {
60
+ :path => 'spec/fixtures/templates/myapp_vpc.json',
61
+ :body => 'file content'
62
+ }
63
+ }
64
+ }
65
+ end
66
+
67
+ it 'uploads files under the bucket root' do
68
+ expect(s3).to receive(:put_object).with(bucket: 'bucket',
69
+ key: 'template',
70
+ body: 'file content',
71
+ metadata: {md5: "d10b4c3ff123b26dc068d43a8bef2d23"})
72
+ s3_driver.upload_files(options)
73
+ end
74
+ end
75
+
76
+ context 'when called with files in a subfolder' do
77
+ let(:options) do
78
+ {
79
+ bucket: 'bucket',
80
+ region: 'region',
81
+ prefix: 'prefix',
82
+ files: {'template' => {
83
+ :path => 'spec/fixtures/templates/myapp_vpc.json',
84
+ :body => 'file content'
85
+ }
86
+ }
87
+ }
88
+ end
89
+
90
+ it 'uploads files under the prefix' do
91
+ expect(s3).to receive(:put_object).with(bucket: 'bucket',
92
+ key: 'prefix/template',
93
+ body: 'file content',
94
+ metadata: {md5: "d10b4c3ff123b26dc068d43a8bef2d23"})
95
+ s3_driver.upload_files(options)
96
+ end
97
+ end
98
+
99
+ context 'when called with several files' do
100
+ let(:options) do
101
+ {
102
+ bucket: 'bucket',
103
+ region: 'region',
104
+ files: {
105
+ 'template1' => {
106
+ :path => 'spec/fixtures/templates/myapp_vpc.json',
107
+ :body => 'file content'
108
+ },
109
+ 'template2' => {
110
+ :path => 'spec/fixtures/templates/myapp_vpc.json',
111
+ :body => 'file content'
112
+ }
113
+ }
114
+ }
115
+ end
116
+
117
+ it 'uploads all the files' do
118
+ expect(s3).to receive(:put_object).with(bucket: 'bucket',
119
+ key: 'template1',
120
+ body: 'file content',
121
+ metadata: {md5: "d10b4c3ff123b26dc068d43a8bef2d23"})
122
+ expect(s3).to receive(:put_object).with(bucket: 'bucket',
123
+ key: 'template2',
124
+ body: 'file content',
125
+ metadata: {md5: "d10b4c3ff123b26dc068d43a8bef2d23"})
126
+ s3_driver.upload_files(options)
127
+ end
128
+ end
129
+ end
130
+ end
@@ -1,5 +1,6 @@
1
1
  RSpec.describe StackMaster::Commands::Apply do
2
2
  let(:cf) { instance_double(Aws::CloudFormation::Client) }
3
+ let(:s3) { instance_double(Aws::S3::Client) }
3
4
  let(:region) { 'us-east-1' }
4
5
  let(:stack_name) { 'myapp-vpc' }
5
6
  let(:config) { double(find_stack: stack_definition) }
@@ -13,7 +14,9 @@ RSpec.describe StackMaster::Commands::Apply do
13
14
  before do
14
15
  allow(StackMaster::Stack).to receive(:find).with(region, stack_name).and_return(stack)
15
16
  allow(StackMaster::Stack).to receive(:generate).with(stack_definition, config).and_return(proposed_stack)
17
+ allow(config).to receive(:stack_defaults).and_return({})
16
18
  allow(Aws::CloudFormation::Client).to receive(:new).and_return(cf)
19
+ allow(Aws::S3::Client).to receive(:new).and_return(s3)
17
20
  allow(cf).to receive(:create_stack)
18
21
  allow(StackMaster::StackDiffer).to receive(:new).with(proposed_stack, stack).and_return double.as_null_object
19
22
  allow(StackMaster::StackEvents::Streamer).to receive(:stream)
@@ -55,6 +58,29 @@ RSpec.describe StackMaster::Commands::Apply do
55
58
  end
56
59
  end
57
60
 
61
+ context 'when using s3' do
62
+ before do
63
+ stack_definition.s3 = {
64
+ 'bucket' => 'my-bucket',
65
+ 'prefix' => 'my-prefix',
66
+ 'region' => 'us-east-1',
67
+ }
68
+ stack_definition.template = 'my-template.rb'
69
+ allow(s3).to receive(:list_objects).and_return([])
70
+ allow(s3).to receive(:put_object)
71
+ end
72
+
73
+ it 'uploads to the correct URL' do
74
+ apply
75
+ expect(s3).to have_received(:put_object).with(
76
+ bucket: 'my-bucket',
77
+ key: 'my-prefix/my-template.json',
78
+ body: template_body,
79
+ metadata: { md5: Digest::MD5.hexdigest(template_body).to_s }
80
+ )
81
+ end
82
+ end
83
+
58
84
  context 'the changeset failed to create' do
59
85
  before do
60
86
  allow(change_set).to receive(:failed?).and_return(true)
@@ -4,9 +4,11 @@ RSpec.describe StackMaster::Config do
4
4
  let(:myapp_vpc_definition) {
5
5
  StackMaster::StackDefinition.new(
6
6
  region: 'us-east-1',
7
+ region_alias: 'production',
7
8
  stack_name: 'myapp-vpc',
8
9
  template: 'myapp_vpc.json',
9
10
  tags: { 'application' => 'my-awesome-blog', 'environment' => 'production' },
11
+ s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' },
10
12
  notification_arns: ['test_arn', 'test_arn_2'],
11
13
  base_dir: base_dir,
12
14
  secret_file: 'production.yml.gpg',
@@ -66,7 +68,8 @@ RSpec.describe StackMaster::Config do
66
68
 
67
69
  it 'loads stack defaults' do
68
70
  expect(loaded_config.stack_defaults).to eq({
69
- 'tags' => { 'application' => 'my-awesome-blog' }
71
+ 'tags' => { 'application' => 'my-awesome-blog' },
72
+ 's3' => { 'bucket' => 'my-bucket', 'region' => 'us-east-1' }
70
73
  })
71
74
  end
72
75
 
@@ -107,11 +110,13 @@ RSpec.describe StackMaster::Config do
107
110
  expect(loaded_config.find_stack('ap-southeast-2', 'myapp-vpc')).to eq(StackMaster::StackDefinition.new(
108
111
  stack_name: 'myapp-vpc',
109
112
  region: 'ap-southeast-2',
113
+ region_alias: 'staging',
110
114
  tags: {
111
115
  'application' => 'my-awesome-blog',
112
116
  'environment' => 'staging',
113
117
  'test_override' => 1
114
118
  },
119
+ s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' },
115
120
  notification_arns: ['test_arn_3', 'test_arn_4'],
116
121
  template: 'myapp_vpc.rb',
117
122
  base_dir: base_dir,
@@ -121,11 +126,13 @@ RSpec.describe StackMaster::Config do
121
126
  expect(loaded_config.find_stack('ap-southeast-2', 'myapp-web')).to eq(StackMaster::StackDefinition.new(
122
127
  stack_name: 'myapp-web',
123
128
  region: 'ap-southeast-2',
129
+ region_alias: 'staging',
124
130
  tags: {
125
131
  'application' => 'my-awesome-blog',
126
132
  'environment' => 'staging',
127
133
  'test_override' => 2
128
134
  },
135
+ s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' },
129
136
  notification_arns: ['test_arn_3'],
130
137
  template: 'myapp_web',
131
138
  base_dir: base_dir,
@@ -38,6 +38,11 @@ RSpec.describe StackMaster::ParameterResolver do
38
38
  expect(resolve(param1: [1, 2])).to eq(param1: '1,2')
39
39
  end
40
40
 
41
+ it 'converts boolean values to strings' do
42
+ expect(resolve(param1: true)).to eq(param1: 'true')
43
+ expect(resolve(param1: false)).to eq(param1: 'false')
44
+ end
45
+
41
46
  it 'it throws an error when the hash contains more than one key' do
42
47
  expect {
43
48
  resolve(param: { nested1: 'value1', nested2: 'value2' })
@@ -1,3 +1,5 @@
1
+ require 'stack_master/sparkle_formation/user_data_file'
2
+
1
3
  RSpec.describe SparkleFormation::SparkleAttribute::Aws, '#user_data_file!' do
2
4
  let(:user_data) do
3
5
  <<-EOS
@@ -12,7 +12,7 @@ RSpec.describe StackMaster::StackEvents::Presenter do
12
12
  subject(:print_event) { described_class.print_event($stdout, event) }
13
13
 
14
14
  it "nicely presents event data" do
15
- expect { print_event }.to output("\e[0;33;49m2001-01-01 02:02:02 #{Time.now.strftime('%z')} MyAwesomeQueue AWS::SQS::Queue CREATE_IN_PROGRESS Resource creation Initiated\e[0m\n").to_stdout
15
+ expect { print_event }.to output("\e[0;33;49m2001-01-01 02:02:02 #{time.strftime('%z')} MyAwesomeQueue AWS::SQS::Queue CREATE_IN_PROGRESS Resource creation Initiated\e[0m\n").to_stdout
16
16
  end
17
17
  end
18
18
  end
@@ -144,14 +144,32 @@ RSpec.describe StackMaster::Stack do
144
144
  end
145
145
 
146
146
  describe '#too_big?' do
147
- let(:big_stack) { described_class.new(template_body: "{\"a\":\"#{'x' * 60000}\"}") }
147
+ let(:big_stack) { described_class.new(template_body: "{\"a\":\"#{'x' * 500000}\"}") }
148
+ let(:medium_stack) { described_class.new(template_body: "{\"a\":\"#{'x' * 60000}\"}") }
148
149
  let(:little_stack) { described_class.new(template_body: "{\"a\":\"#{'x' * 1000}\"}") }
149
150
 
150
- it 'returns true for big stacks' do
151
- expect(big_stack.too_big?).to be_truthy
151
+ context 'when not using S3' do
152
+ it 'returns true for big stacks' do
153
+ expect(big_stack.too_big?).to be_truthy
154
+ end
155
+ it 'returns true for medium stacks' do
156
+ expect(medium_stack.too_big?).to be_truthy
157
+ end
158
+ it 'returns false for small stacks' do
159
+ expect(little_stack.too_big?).to be_falsey
160
+ end
152
161
  end
153
- it 'returns false for small stacks' do
154
- expect(little_stack.too_big?).to be_falsey
162
+
163
+ context 'when using S3' do
164
+ it 'returns true for big stacks' do
165
+ expect(big_stack.too_big?(true)).to be_truthy
166
+ end
167
+ it 'returns false for medium stacks' do
168
+ expect(medium_stack.too_big?(true)).to be_falsey
169
+ end
170
+ it 'returns false for small stacks' do
171
+ expect(little_stack.too_big?(true)).to be_falsey
172
+ end
155
173
  end
156
174
  end
157
175
 
@@ -4,6 +4,7 @@ RSpec.describe StackMaster::TemplateCompiler do
4
4
  let(:template_file_path) { '/base_dir/templates/template.fab' }
5
5
 
6
6
  class TestTemplateCompiler
7
+ def self.require_dependencies; end
7
8
  def self.compile(template_file_path); end
8
9
  end
9
10
 
@@ -1,4 +1,6 @@
1
1
  RSpec.describe StackMaster::TemplateCompilers::Cfndsl do
2
+ before(:all) { described_class.require_dependencies }
3
+
2
4
  describe '.compile' do
3
5
  def compile
4
6
  described_class.compile(template_file_path)
@@ -0,0 +1,17 @@
1
+ RSpec.describe StackMaster::TestDriver::S3 do
2
+ subject(:s3_driver) { described_class.new }
3
+ let(:bucket) { 'test-bucket' }
4
+ let(:prefix) { 'test-prefix' }
5
+ let(:files) { { 'test-file' => { path: 'path', body: 'body' } } }
6
+ let(:region) { 'us-east-1' }
7
+
8
+ it 'uploads and finds files' do
9
+ s3_driver.upload_files(bucket: bucket,
10
+ prefix: prefix,
11
+ region: region,
12
+ files: files)
13
+ file = s3_driver.find_file(bucket: bucket,
14
+ object_key: [prefix, 'test-file'].compact.join('/'))
15
+ expect(file).to be
16
+ end
17
+ end
data/stack_master.gemspec CHANGED
@@ -27,7 +27,6 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency "timecop"
28
28
  spec.add_dependency "ruby-progressbar"
29
29
  spec.add_dependency "commander"
30
- spec.add_dependency "virtus"
31
30
  spec.add_dependency "aws-sdk", "~> 2.2.31"
32
31
  spec.add_dependency "diffy"
33
32
  spec.add_dependency "erubis"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stack_master
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Hodgkiss
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-07-15 00:00:00.000000000 Z
12
+ date: 2016-07-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -137,20 +137,6 @@ dependencies:
137
137
  - - ">="
138
138
  - !ruby/object:Gem::Version
139
139
  version: '0'
140
- - !ruby/object:Gem::Dependency
141
- name: virtus
142
- requirement: !ruby/object:Gem::Requirement
143
- requirements:
144
- - - ">="
145
- - !ruby/object:Gem::Version
146
- version: '0'
147
- type: :runtime
148
- prerelease: false
149
- version_requirements: !ruby/object:Gem::Requirement
150
- requirements:
151
- - - ">="
152
- - !ruby/object:Gem::Version
153
- version: '0'
154
140
  - !ruby/object:Gem::Dependency
155
141
  name: aws-sdk
156
142
  requirement: !ruby/object:Gem::Requirement
@@ -316,6 +302,7 @@ files:
316
302
  - example/simple/templates/myapp_vpc.rb
317
303
  - example/simple/templates/myapp_web.rb
318
304
  - features/apply.feature
305
+ - features/apply_with_s3.feature
319
306
  - features/delete.feature
320
307
  - features/diff.feature
321
308
  - features/events.feature
@@ -330,6 +317,7 @@ files:
330
317
  - features/validate.feature
331
318
  - lib/stack_master.rb
332
319
  - lib/stack_master/aws_driver/cloud_formation.rb
320
+ - lib/stack_master/aws_driver/s3.rb
333
321
  - lib/stack_master/change_set.rb
334
322
  - lib/stack_master/cli.rb
335
323
  - lib/stack_master/command.rb
@@ -375,6 +363,7 @@ files:
375
363
  - lib/stack_master/template_compilers/sparkle_formation.rb
376
364
  - lib/stack_master/template_compilers/yaml.rb
377
365
  - lib/stack_master/test_driver/cloud_formation.rb
366
+ - lib/stack_master/test_driver/s3.rb
378
367
  - lib/stack_master/testing.rb
379
368
  - lib/stack_master/utils.rb
380
369
  - lib/stack_master/validator.rb
@@ -392,6 +381,7 @@ files:
392
381
  - spec/fixtures/templates/yml/valid_myapp_vpc.yml
393
382
  - spec/fixtures/test/.gitkeep
394
383
  - spec/spec_helper.rb
384
+ - spec/stack_master/aws_driver/s3_spec.rb
395
385
  - spec/stack_master/change_set_spec.rb
396
386
  - spec/stack_master/command_spec.rb
397
387
  - spec/stack_master/commands/apply_spec.rb
@@ -428,6 +418,7 @@ files:
428
418
  - spec/stack_master/template_compilers/sparkle_formation_spec.rb
429
419
  - spec/stack_master/template_compilers/yaml_spec.rb
430
420
  - spec/stack_master/test_driver/cloud_formation_spec.rb
421
+ - spec/stack_master/test_driver/s3_spec.rb
431
422
  - spec/stack_master/utils_spec.rb
432
423
  - spec/stack_master/validator_spec.rb
433
424
  - spec/stack_master_spec.rb
@@ -463,6 +454,7 @@ summary: StackMaster is a sure-footed way of creating, updating and keeping trac
463
454
  of Amazon (AWS) CloudFormation stacks.
464
455
  test_files:
465
456
  - features/apply.feature
457
+ - features/apply_with_s3.feature
466
458
  - features/delete.feature
467
459
  - features/diff.feature
468
460
  - features/events.feature
@@ -484,6 +476,7 @@ test_files:
484
476
  - spec/fixtures/templates/yml/valid_myapp_vpc.yml
485
477
  - spec/fixtures/test/.gitkeep
486
478
  - spec/spec_helper.rb
479
+ - spec/stack_master/aws_driver/s3_spec.rb
487
480
  - spec/stack_master/change_set_spec.rb
488
481
  - spec/stack_master/command_spec.rb
489
482
  - spec/stack_master/commands/apply_spec.rb
@@ -520,6 +513,7 @@ test_files:
520
513
  - spec/stack_master/template_compilers/sparkle_formation_spec.rb
521
514
  - spec/stack_master/template_compilers/yaml_spec.rb
522
515
  - spec/stack_master/test_driver/cloud_formation_spec.rb
516
+ - spec/stack_master/test_driver/s3_spec.rb
523
517
  - spec/stack_master/utils_spec.rb
524
518
  - spec/stack_master/validator_spec.rb
525
519
  - spec/stack_master_spec.rb