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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d2df973e8c51854049665bee6f11cff19b8a7aba
4
- data.tar.gz: 2ce1a8f1de5d06e02a47aef292648d79c2c52d21
3
+ metadata.gz: a51b4fe56605619be180809d3e8b936beba108c0
4
+ data.tar.gz: 479573ec4534231f8cc2dad7a1d7396f240c3ed6
5
5
  SHA512:
6
- metadata.gz: 869faae3d938ae4cee9e9e666c25077a308220eaa7544fb8a9e78aeeb6df9870df541871102651a3c45efef0f1258490b50be49f48f6bf68d733e5a57001e85e
7
- data.tar.gz: b2958b04187ad83dea0e22909f07a66219214080ce097715d02a06775987dc0f86e86bd55482305e9cb8de59a86e4e02c371cab6834a6ff809cafcaec9280a16
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.10
4
+ - rvm: 2.1
5
5
  gemfile: spec/support/gemfiles/Gemfile.activesupport-4.0.0
6
- - rvm: 2.2.7
7
- - rvm: 2.3.4
8
- - rvm: 2.4.1
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.
@@ -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 "Proposed change set:"
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}.yml")
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}.yml")
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}.yml")
96
+ Dir.glob(File.join(base_dir, 'parameters', "#{underscored_stack_name}.y*ml"))
97
97
  end
98
98
 
99
99
  def underscored_stack_name
@@ -1,3 +1,3 @@
1
1
  module StackMaster
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -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}.yml"
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}.yml"
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.1
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: 2017-12-15 00:00:00.000000000 Z
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