stack_master 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -4
- data/README.md +17 -1
- data/features/apply.feature +2 -0
- data/features/apply_with_env_parameters.feature +49 -0
- data/lib/stack_master.rb +1 -0
- data/lib/stack_master/change_set.rb +6 -1
- data/lib/stack_master/parameter_resolvers/env.rb +18 -0
- data/lib/stack_master/stack_definition.rb +3 -3
- data/lib/stack_master/version.rb +1 -1
- data/spec/stack_master/parameter_loader_spec.rb +17 -0
- data/spec/stack_master/parameter_resolvers/env_spec.rb +35 -0
- data/spec/stack_master/stack_definition_spec.rb +35 -2
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a51b4fe56605619be180809d3e8b936beba108c0
|
4
|
+
data.tar.gz: 479573ec4534231f8cc2dad7a1d7396f240c3ed6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c7784db458ab74af7d4b7d1b18c4603c1227d73574d1624d013fded5bb6af8ec2f74239b7d30b50085fb6c5b781f62a46905b89f883fe00a77bc469621cdb8e
|
7
|
+
data.tar.gz: e5244c0803bd55d3462fb02f79d239a6b240fd3ca7dd88649021097bc0b20c9ac97fa5e9070667ef5a5d7e3bcc6f3a94cb2ec733a02329692f3fea66719da605
|
data/.travis.yml
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
language: ruby
|
2
2
|
matrix:
|
3
3
|
include:
|
4
|
-
- rvm: 2.1
|
4
|
+
- rvm: 2.1
|
5
5
|
gemfile: spec/support/gemfiles/Gemfile.activesupport-4.0.0
|
6
|
-
- rvm: 2.2
|
7
|
-
- rvm: 2.3
|
8
|
-
- rvm: 2.4
|
6
|
+
- rvm: 2.2
|
7
|
+
- rvm: 2.3
|
8
|
+
- rvm: 2.4
|
9
|
+
- rvm: 2.5
|
9
10
|
sudo: false
|
10
11
|
script:
|
11
12
|
- bundle exec rake spec features
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
![StackMaster](/logo.png?raw=true)
|
2
2
|
|
3
|
+
[![License MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/envato/stack_master/blob/master/LICENSE.md)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/stack_master.svg)](https://badge.fury.io/rb/stack_master)
|
5
|
+
[![Build Status](https://travis-ci.org/envato/stack_master.svg?branch=master)](https://travis-ci.org/envato/stack_master)
|
6
|
+
|
3
7
|
StackMaster is a CLI tool to manage CloudFormation stacks, with the following features:
|
4
8
|
|
5
9
|
- Synchronous visibility into stack updates. See exactly what is changing and
|
@@ -143,10 +147,13 @@ template_compilers:
|
|
143
147
|
|
144
148
|
## Parameters
|
145
149
|
|
146
|
-
Parameters are loaded from multiple YAML files, merged from the following lookup paths:
|
150
|
+
Parameters are loaded from multiple YAML files, merged from the following lookup paths from bottom to top:
|
147
151
|
|
152
|
+
- parameters/[stack_name].yaml
|
148
153
|
- parameters/[stack_name].yml
|
154
|
+
- parameters/[region]/[underscored_stack_name].yaml
|
149
155
|
- parameters/[region]/[underscored_stack_name].yml
|
156
|
+
- parameters/[region_alias]/[underscored_stack_name].yaml
|
150
157
|
- parameters/[region_alias]/[underscored_stack_name].yml
|
151
158
|
|
152
159
|
A simple parameter file could look like this:
|
@@ -290,6 +297,15 @@ A set of possible attributes is available in the [AWS documentation](https://doc
|
|
290
297
|
|
291
298
|
Any value can be an array of possible matches.
|
292
299
|
|
300
|
+
### Environment Variable
|
301
|
+
|
302
|
+
Lookup an environment variable:
|
303
|
+
|
304
|
+
```yaml
|
305
|
+
db_username:
|
306
|
+
env: DB_USERNAME
|
307
|
+
```
|
308
|
+
|
293
309
|
### Custom parameter resolvers
|
294
310
|
|
295
311
|
New parameter resolvers can be created in a separate gem.
|
data/features/apply.feature
CHANGED
@@ -207,8 +207,10 @@ Feature: Apply command
|
|
207
207
|
| Stack diff: |
|
208
208
|
| - "TestSg2": { |
|
209
209
|
| Parameters diff: No changes |
|
210
|
+
| ======================================== |
|
210
211
|
| Proposed change set: |
|
211
212
|
| Replace |
|
213
|
+
| ======================================== |
|
212
214
|
| Apply change set (y/n)? |
|
213
215
|
Then the exit status should be 0
|
214
216
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
Feature: Apply command with environment parameter
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a file named "stack_master.yml" with:
|
5
|
+
"""
|
6
|
+
stacks:
|
7
|
+
us-east-2:
|
8
|
+
vpc:
|
9
|
+
template: vpc.rb
|
10
|
+
"""
|
11
|
+
And a directory named "parameters"
|
12
|
+
And a file named "parameters/vpc.yml" with:
|
13
|
+
"""
|
14
|
+
vpc_cidr:
|
15
|
+
env: VPC_CIDR
|
16
|
+
"""
|
17
|
+
And a directory named "templates"
|
18
|
+
And a file named "templates/vpc.rb" with:
|
19
|
+
"""
|
20
|
+
SparkleFormation.new(:vpc) do
|
21
|
+
|
22
|
+
parameters.vpc_cidr do
|
23
|
+
type 'String'
|
24
|
+
end
|
25
|
+
|
26
|
+
resources.vpc do
|
27
|
+
type 'AWS::EC2::VPC'
|
28
|
+
properties do
|
29
|
+
cidr_block ref!(:vpc_cidr)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
"""
|
35
|
+
|
36
|
+
Scenario: Run apply and create a new stack
|
37
|
+
Given I stub the following stack events:
|
38
|
+
| stack_id | event_id | stack_name | logical_resource_id | resource_status | resource_type | timestamp |
|
39
|
+
| 1 | 1 | vpc | Vpc | CREATE_COMPLETE | AWS::EC2::VPC | 2020-10-29 00:00:00 |
|
40
|
+
| 1 | 1 | vpc | vpc | CREATE_COMPLETE | AWS::CloudFormation::Stack | 2020-10-29 00:00:00 |
|
41
|
+
And I set the environment variables to:
|
42
|
+
| variable | value |
|
43
|
+
| VPC_CIDR | 10.0.0.0/16 |
|
44
|
+
When I run `stack_master apply us-east-2 vpc --trace`
|
45
|
+
And the output should contain all of these lines:
|
46
|
+
| +--- |
|
47
|
+
| +VpcCidr: 10.0.0.0/16 |
|
48
|
+
And the output should match /2020-10-29 00:00:00 (\+|\-)[0-9]{4} vpc AWS::CloudFormation::Stack CREATE_COMPLETE/
|
49
|
+
Then the exit status should be 0
|
data/lib/stack_master.rb
CHANGED
@@ -60,6 +60,7 @@ module StackMaster
|
|
60
60
|
autoload :SecurityGroup, 'stack_master/parameter_resolvers/security_group'
|
61
61
|
autoload :LatestAmiByTags, 'stack_master/parameter_resolvers/latest_ami_by_tags'
|
62
62
|
autoload :LatestAmi, 'stack_master/parameter_resolvers/latest_ami'
|
63
|
+
autoload :Env, 'stack_master/parameter_resolvers/env'
|
63
64
|
end
|
64
65
|
|
65
66
|
module AwsDriver
|
@@ -42,10 +42,15 @@ module StackMaster
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def display(io)
|
45
|
-
io.puts
|
45
|
+
io.puts <<-EOL
|
46
|
+
|
47
|
+
========================================
|
48
|
+
Proposed change set:
|
49
|
+
EOL
|
46
50
|
@response.changes.each do |change|
|
47
51
|
display_resource_change(io, change.resource_change)
|
48
52
|
end
|
53
|
+
io.puts "========================================"
|
49
54
|
end
|
50
55
|
|
51
56
|
def failed?
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module StackMaster
|
2
|
+
module ParameterResolvers
|
3
|
+
class Env < Resolver
|
4
|
+
|
5
|
+
def initialize(config, stack_definition)
|
6
|
+
@config = config
|
7
|
+
@stack_definition = stack_definition
|
8
|
+
end
|
9
|
+
|
10
|
+
def resolve(value)
|
11
|
+
environment_variable = ENV[value]
|
12
|
+
raise ArgumentError, "The environment variable #{value} is not set" if environment_variable.nil?
|
13
|
+
environment_variable
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -84,16 +84,16 @@ module StackMaster
|
|
84
84
|
def additional_parameter_lookup_file_paths
|
85
85
|
return unless additional_parameter_lookup_dirs
|
86
86
|
additional_parameter_lookup_dirs.map do |a|
|
87
|
-
File.join(base_dir, 'parameters', a, "#{underscored_stack_name}.
|
87
|
+
Dir.glob(File.join(base_dir, 'parameters', a, "#{underscored_stack_name}.y*ml"))
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
91
|
def region_parameter_file_path
|
92
|
-
File.join(base_dir, 'parameters', "#{region}", "#{underscored_stack_name}.
|
92
|
+
Dir.glob(File.join(base_dir, 'parameters', "#{region}", "#{underscored_stack_name}.y*ml"))
|
93
93
|
end
|
94
94
|
|
95
95
|
def default_parameter_file_path
|
96
|
-
File.join(base_dir, 'parameters', "#{underscored_stack_name}.
|
96
|
+
Dir.glob(File.join(base_dir, 'parameters', "#{underscored_stack_name}.y*ml"))
|
97
97
|
end
|
98
98
|
|
99
99
|
def underscored_stack_name
|
data/lib/stack_master/version.rb
CHANGED
@@ -54,6 +54,23 @@ RSpec.describe StackMaster::ParameterLoader do
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
context 'yml and yaml region parameter files' do
|
58
|
+
let(:stack_file_returns) { {exists: false} }
|
59
|
+
let(:region_file_returns) { {exists: true, read: "Param2: value2"} }
|
60
|
+
let(:region_yaml_file_returns) { {exists: true, read: "Param1: value1\nParam2: valueX"} }
|
61
|
+
let(:region_yaml_file_name) { "/base_dir/parameters/us-east-1/stack_name.yaml" }
|
62
|
+
|
63
|
+
subject(:parameters) { StackMaster::ParameterLoader.load([stack_file_name, region_yaml_file_name, region_file_name]) }
|
64
|
+
|
65
|
+
before do
|
66
|
+
file_mock(region_yaml_file_name, region_yaml_file_returns)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns params from the region base stack_name.yml' do
|
70
|
+
expect(parameters).to eq(template_parameters: {'Param1' => 'value1', 'Param2' => 'value2'}, compile_time_parameters: {})
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
57
74
|
context 'compile time parameters' do
|
58
75
|
|
59
76
|
context 'stack parameter file' do
|
@@ -0,0 +1,35 @@
|
|
1
|
+
RSpec.describe StackMaster::ParameterResolvers::Env do
|
2
|
+
|
3
|
+
describe '#resolve' do
|
4
|
+
|
5
|
+
subject(:resolver) { described_class.new(nil, double(region: 'us-east-1')) }
|
6
|
+
let(:environment_variable_name) { 'TEST' }
|
7
|
+
let(:error) { "The environment variable #{environment_variable_name} is not set" }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
ENV.delete(environment_variable_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'the environment variable is defined' do
|
14
|
+
it 'should return the environment variable value' do
|
15
|
+
ENV[environment_variable_name] = 'a'
|
16
|
+
expect(resolver.resolve(environment_variable_name)).to eq 'a'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'the environment variable is undefined' do
|
21
|
+
it 'should raise and error' do
|
22
|
+
expect { resolver.resolve(environment_variable_name) }
|
23
|
+
.to raise_error(ArgumentError, error)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'the environment variable is defined but empty' do
|
28
|
+
it 'should return the empty string' do
|
29
|
+
ENV[environment_variable_name] = ''
|
30
|
+
expect(resolver.resolve(environment_variable_name)).to eq ''
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -14,23 +14,56 @@ RSpec.describe StackMaster::StackDefinition do
|
|
14
14
|
let(:tags) { {'environment' => 'production'} }
|
15
15
|
let(:base_dir) { '/base_dir' }
|
16
16
|
|
17
|
+
before do
|
18
|
+
allow(Dir).to receive(:glob).with(
|
19
|
+
File.join(base_dir, 'parameters', "#{stack_name}.y*ml")
|
20
|
+
).and_return(
|
21
|
+
[
|
22
|
+
"/base_dir/parameters/#{stack_name}.yaml",
|
23
|
+
"/base_dir/parameters/#{stack_name}.yml",
|
24
|
+
]
|
25
|
+
)
|
26
|
+
|
27
|
+
allow(Dir).to receive(:glob).with(
|
28
|
+
File.join(base_dir, 'parameters', "#{region}", "#{stack_name}.y*ml")
|
29
|
+
).and_return(
|
30
|
+
[
|
31
|
+
"/base_dir/parameters/#{region}/#{stack_name}.yaml",
|
32
|
+
"/base_dir/parameters/#{region}/#{stack_name}.yml",
|
33
|
+
]
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
17
37
|
it 'has default and region specific parameter file locations' do
|
18
38
|
expect(stack_definition.parameter_files).to eq([
|
39
|
+
"/base_dir/parameters/#{stack_name}.yaml",
|
19
40
|
"/base_dir/parameters/#{stack_name}.yml",
|
20
|
-
"/base_dir/parameters/#{region}/#{stack_name}.
|
41
|
+
"/base_dir/parameters/#{region}/#{stack_name}.yaml",
|
42
|
+
"/base_dir/parameters/#{region}/#{stack_name}.yml",
|
21
43
|
])
|
22
44
|
end
|
23
45
|
|
24
46
|
context 'with additional parameter lookup dirs' do
|
25
47
|
before do
|
26
48
|
stack_definition.send(:additional_parameter_lookup_dirs=, ['production'])
|
49
|
+
allow(Dir).to receive(:glob).with(
|
50
|
+
File.join(base_dir, 'parameters', "production", "#{stack_name}.y*ml")
|
51
|
+
).and_return(
|
52
|
+
[
|
53
|
+
"/base_dir/parameters/production/#{stack_name}.yaml",
|
54
|
+
"/base_dir/parameters/production/#{stack_name}.yml",
|
55
|
+
]
|
56
|
+
)
|
27
57
|
end
|
28
58
|
|
29
59
|
it 'includes a parameter lookup dir for it' do
|
30
60
|
expect(stack_definition.parameter_files).to eq([
|
61
|
+
"/base_dir/parameters/#{stack_name}.yaml",
|
31
62
|
"/base_dir/parameters/#{stack_name}.yml",
|
63
|
+
"/base_dir/parameters/#{region}/#{stack_name}.yaml",
|
32
64
|
"/base_dir/parameters/#{region}/#{stack_name}.yml",
|
33
|
-
"/base_dir/parameters/production/#{stack_name}.
|
65
|
+
"/base_dir/parameters/production/#{stack_name}.yaml",
|
66
|
+
"/base_dir/parameters/production/#{stack_name}.yml",
|
34
67
|
])
|
35
68
|
end
|
36
69
|
end
|
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: 1.0
|
4
|
+
version: 1.1.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:
|
12
|
+
date: 2018-02-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -303,6 +303,7 @@ files:
|
|
303
303
|
- example/simple/templates/myapp_web.rb
|
304
304
|
- features/apply.feature
|
305
305
|
- features/apply_with_compile_time_parameters.feature
|
306
|
+
- features/apply_with_env_parameters.feature
|
306
307
|
- features/apply_with_s3.feature
|
307
308
|
- features/delete.feature
|
308
309
|
- features/diff.feature
|
@@ -339,6 +340,7 @@ files:
|
|
339
340
|
- lib/stack_master/parameter_loader.rb
|
340
341
|
- lib/stack_master/parameter_resolver.rb
|
341
342
|
- lib/stack_master/parameter_resolvers/ami_finder.rb
|
343
|
+
- lib/stack_master/parameter_resolvers/env.rb
|
342
344
|
- lib/stack_master/parameter_resolvers/latest_ami.rb
|
343
345
|
- lib/stack_master/parameter_resolvers/latest_ami_by_tags.rb
|
344
346
|
- lib/stack_master/parameter_resolvers/secret.rb
|
@@ -412,6 +414,7 @@ files:
|
|
412
414
|
- spec/stack_master/parameter_loader_spec.rb
|
413
415
|
- spec/stack_master/parameter_resolver_spec.rb
|
414
416
|
- spec/stack_master/parameter_resolvers/ami_finder_spec.rb
|
417
|
+
- spec/stack_master/parameter_resolvers/env_spec.rb
|
415
418
|
- spec/stack_master/parameter_resolvers/latest_ami_by_tags_spec.rb
|
416
419
|
- spec/stack_master/parameter_resolvers/latest_ami_spec.rb
|
417
420
|
- spec/stack_master/parameter_resolvers/secret_spec.rb
|
@@ -490,6 +493,7 @@ summary: StackMaster is a sure-footed way of creating, updating and keeping trac
|
|
490
493
|
test_files:
|
491
494
|
- features/apply.feature
|
492
495
|
- features/apply_with_compile_time_parameters.feature
|
496
|
+
- features/apply_with_env_parameters.feature
|
493
497
|
- features/apply_with_s3.feature
|
494
498
|
- features/delete.feature
|
495
499
|
- features/diff.feature
|
@@ -526,6 +530,7 @@ test_files:
|
|
526
530
|
- spec/stack_master/parameter_loader_spec.rb
|
527
531
|
- spec/stack_master/parameter_resolver_spec.rb
|
528
532
|
- spec/stack_master/parameter_resolvers/ami_finder_spec.rb
|
533
|
+
- spec/stack_master/parameter_resolvers/env_spec.rb
|
529
534
|
- spec/stack_master/parameter_resolvers/latest_ami_by_tags_spec.rb
|
530
535
|
- spec/stack_master/parameter_resolvers/latest_ami_spec.rb
|
531
536
|
- spec/stack_master/parameter_resolvers/secret_spec.rb
|