stack_master 0.17.0 → 0.18.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 +7 -5
- data/README.md +15 -0
- data/features/apply.feature +0 -1
- data/features/apply_with_compile_time_parameters.feature +93 -0
- data/lib/stack_master/parameter_loader.rb +41 -12
- data/lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb +35 -0
- data/lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb +37 -0
- data/lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb +33 -0
- data/lib/stack_master/sparkle_formation/compile_time/empty_validator.rb +32 -0
- data/lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/number_validator.rb +35 -0
- data/lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb +27 -0
- data/lib/stack_master/sparkle_formation/compile_time/state_builder.rb +32 -0
- data/lib/stack_master/sparkle_formation/compile_time/string_validator.rb +33 -0
- data/lib/stack_master/sparkle_formation/compile_time/value_builder.rb +40 -0
- data/lib/stack_master/sparkle_formation/compile_time/value_validator.rb +40 -0
- data/lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb +41 -0
- data/lib/stack_master/stack.rb +4 -3
- data/lib/stack_master/template_compiler.rb +2 -2
- data/lib/stack_master/template_compilers/cfndsl.rb +1 -1
- data/lib/stack_master/template_compilers/json.rb +1 -1
- data/lib/stack_master/template_compilers/sparkle_formation.rb +33 -4
- data/lib/stack_master/template_compilers/yaml.rb +1 -1
- data/lib/stack_master/validator.rb +4 -1
- data/lib/stack_master/version.rb +1 -1
- data/spec/spec_helper.rb +3 -0
- data/spec/stack_master/parameter_loader_spec.rb +65 -53
- data/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb +47 -0
- data/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb +47 -0
- data/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb +36 -0
- data/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb +47 -0
- data/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb +37 -0
- data/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb +27 -0
- data/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb +36 -0
- data/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb +28 -0
- data/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb +41 -0
- data/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb +65 -0
- data/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb +28 -0
- data/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb +35 -0
- data/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb +52 -0
- data/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb +40 -0
- data/spec/stack_master/stack_spec.rb +15 -13
- data/spec/stack_master/template_compiler_spec.rb +7 -6
- data/spec/stack_master/template_compilers/cfndsl_spec.rb +4 -1
- data/spec/stack_master/template_compilers/json_spec.rb +4 -1
- data/spec/stack_master/template_compilers/sparkle_formation_spec.rb +53 -9
- data/spec/stack_master/template_compilers/yaml_spec.rb +4 -1
- data/spec/stack_master/validator_spec.rb +10 -6
- data/spec/support/gemfiles/Gemfile.activesupport-4.0.0 +5 -0
- data/spec/support/validator_spec.rb +23 -0
- data/stack_master.gemspec +1 -1
- metadata +55 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce12082b568677adbd824876ec9bdc2c64e399f8
|
4
|
+
data.tar.gz: 854fe4aa23253b1ae5eaec64b1f8ac6fbef97ac1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 598cd004f968afdc315d4d5132e63d5c430180102b7d0ea6299163ce143ff0d5682dd0c13d84bd35e3044c981250750539624793f132bc8d9aed271475adf5b2
|
7
|
+
data.tar.gz: e395e0c8ea148cac6a14c82680463539d4143751e2f673323e6e8b7b221dcdaea6c3f2d1853fdb31afa773b774d33f4a55adf7d3cdaf23d3d528af2f64f71d79
|
data/.travis.yml
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
matrix:
|
3
|
+
include:
|
4
|
+
- rvm: 2.1.10
|
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
|
7
9
|
sudo: false
|
8
10
|
script:
|
9
11
|
- bundle exec rake spec features
|
data/README.md
CHANGED
@@ -155,6 +155,21 @@ A simple parameter file could look like this:
|
|
155
155
|
key_name: myapp-us-east-1
|
156
156
|
```
|
157
157
|
|
158
|
+
### Compile Time Parameters
|
159
|
+
|
160
|
+
Compile time parameters can be used for [SparkleFormation](http://www.sparkleformation.io) templates. It conforms and
|
161
|
+
allows you to use the [Compile Time Parameters](http://www.sparkleformation.io/docs/sparkle_formation/compile-time-parameters.html) feature
|
162
|
+
|
163
|
+
A simple example looks like this
|
164
|
+
|
165
|
+
```
|
166
|
+
vpc_cidr: 10.0.0.0/16
|
167
|
+
compile_time_parameters:
|
168
|
+
subnet_cidrs:
|
169
|
+
- 10.0.0.0/28
|
170
|
+
- 10.0.2.0/28
|
171
|
+
```
|
172
|
+
|
158
173
|
Keys in parameter files are automatically converted to camel case.
|
159
174
|
|
160
175
|
## Parameter Resolvers
|
data/features/apply.feature
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
Feature: Apply command with compile time parameters
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a file named "stack_master.yml" with:
|
5
|
+
"""
|
6
|
+
stacks:
|
7
|
+
us-east-1:
|
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: 10.200.2.0/23
|
15
|
+
compile_time_parameters:
|
16
|
+
private_subnet_cidrs:
|
17
|
+
- 10.0.0.0/32:ap-southeast-2
|
18
|
+
- 10.0.0.2/32:ap-southeast-1
|
19
|
+
"""
|
20
|
+
And a directory named "templates"
|
21
|
+
And a file named "templates/vpc.rb" with:
|
22
|
+
"""
|
23
|
+
SparkleFormation.new(
|
24
|
+
:vpc,
|
25
|
+
{
|
26
|
+
compile_time_parameters: {
|
27
|
+
private_subnet_cidrs: {
|
28
|
+
type: :string,
|
29
|
+
multiple: true
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
) do
|
34
|
+
|
35
|
+
parameters.vpc_cidr do
|
36
|
+
type 'String'
|
37
|
+
end
|
38
|
+
|
39
|
+
resources.vpc do
|
40
|
+
type 'AWS::EC2::VPC'
|
41
|
+
properties do
|
42
|
+
cidr_block ref!(:vpc_cidr)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
state!(:private_subnet_cidrs).each_with_index do |item, index|
|
47
|
+
private_subnet = item.split(':')
|
48
|
+
private_cidr = private_subnet[0]
|
49
|
+
private_az = private_subnet[1]
|
50
|
+
resources.set!("subnet_private_#{index}".to_sym) do
|
51
|
+
type 'AWS::EC2::Subnet'
|
52
|
+
properties do
|
53
|
+
vpc_id ref!(:vpc)
|
54
|
+
availability_zone private_az
|
55
|
+
cidr_block private_cidr
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
"""
|
62
|
+
|
63
|
+
Scenario: Run apply and create a new stack
|
64
|
+
Given I stub the following stack events:
|
65
|
+
| stack_id | event_id | stack_name | logical_resource_id | resource_status | resource_type | timestamp |
|
66
|
+
| 1 | 1 | vpc | SubnetPrivate1 | CREATE_COMPLETE | AWS::EC2::Subnet | 2020-10-29 00:00:00 |
|
67
|
+
| 1 | 1 | vpc | SubnetPrivate0 | CREATE_COMPLETE | AWS::EC2::Subnet | 2020-10-29 00:00:00 |
|
68
|
+
| 1 | 1 | vpc | Vpc | CREATE_COMPLETE | AWS::EC2::VPC | 2020-10-29 00:00:00 |
|
69
|
+
| 1 | 1 | vpc | vpc | CREATE_COMPLETE | AWS::CloudFormation::Stack | 2020-10-29 00:00:00 |
|
70
|
+
When I run `stack_master apply us-east-1 vpc --trace`
|
71
|
+
And the output should contain all of these lines:
|
72
|
+
| + "SubnetPrivate0": { |
|
73
|
+
| + "Type": "AWS::EC2::Subnet", |
|
74
|
+
| + "Properties": { |
|
75
|
+
| + "VpcId": { |
|
76
|
+
| + "Ref": "Vpc" |
|
77
|
+
| + }, |
|
78
|
+
| + "AvailabilityZone": "ap-southeast-2", |
|
79
|
+
| + "CidrBlock": "10.0.0.0/32" |
|
80
|
+
| + } |
|
81
|
+
| + }, |
|
82
|
+
| + "SubnetPrivate1": { |
|
83
|
+
| + "Type": "AWS::EC2::Subnet", |
|
84
|
+
| + "Properties": { |
|
85
|
+
| + "VpcId": { |
|
86
|
+
| + "Ref": "Vpc" |
|
87
|
+
| + }, |
|
88
|
+
| + "AvailabilityZone": "ap-southeast-1", |
|
89
|
+
| + "CidrBlock": "10.0.0.2/32" |
|
90
|
+
| + } |
|
91
|
+
| + } |
|
92
|
+
And the output should match /2020-10-29 00:00:00 (\+|\-)[0-9]{4} vpc AWS::CloudFormation::Stack CREATE_COMPLETE/
|
93
|
+
Then the exit status should be 0
|
@@ -1,20 +1,49 @@
|
|
1
|
+
require 'active_support/core_ext/object/deep_dup'
|
2
|
+
|
1
3
|
module StackMaster
|
2
4
|
class ParameterLoader
|
5
|
+
|
6
|
+
COMPILE_TIME_PARAMETERS_KEY = 'compile_time_parameters'
|
7
|
+
|
3
8
|
def self.load(parameter_files)
|
4
|
-
StackMaster.debug
|
5
|
-
parameter_files.reduce({}) do |hash, file_name|
|
6
|
-
parameters =
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
parameters.each do |key, value|
|
14
|
-
hash[key.camelize] = value
|
15
|
-
end
|
9
|
+
StackMaster.debug 'Searching for parameter files...'
|
10
|
+
parameter_files.reduce({template_parameters: {}, compile_time_parameters: {}}) do |hash, file_name|
|
11
|
+
parameters = load_parameters(file_name)
|
12
|
+
template_parameters = create_template_parameters(parameters)
|
13
|
+
compile_time_parameters = create_compile_time_parameters(parameters)
|
14
|
+
|
15
|
+
merge_and_camelize(hash[:template_parameters], template_parameters)
|
16
|
+
merge_and_camelize(hash[:compile_time_parameters], compile_time_parameters)
|
16
17
|
hash
|
17
18
|
end
|
19
|
+
|
18
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def self.load_parameters(file_name)
|
25
|
+
file_exists = File.exists?(file_name)
|
26
|
+
StackMaster.debug file_exists ? " #{file_name} found" : " #{file_name} not found"
|
27
|
+
file_exists ? load_file(file_name) : {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.load_file(file_name)
|
31
|
+
YAML.load(File.read(file_name)) || {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.create_template_parameters(parameters)
|
35
|
+
parameters.deep_dup.tap do |parameters_clone|
|
36
|
+
parameters_clone.delete(COMPILE_TIME_PARAMETERS_KEY) || parameters_clone.delete(COMPILE_TIME_PARAMETERS_KEY.camelize)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.create_compile_time_parameters(parameters)
|
41
|
+
(parameters[COMPILE_TIME_PARAMETERS_KEY] || parameters[COMPILE_TIME_PARAMETERS_KEY.camelize] || {}).deep_dup
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.merge_and_camelize(hash, parameters)
|
45
|
+
parameters.each { |key, value| hash[key.camelize] = value }
|
46
|
+
end
|
47
|
+
|
19
48
|
end
|
20
49
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'value_validator'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
module SparkleFormation
|
5
|
+
module CompileTime
|
6
|
+
class AllowedPatternValidator < ValueValidator
|
7
|
+
|
8
|
+
KEY = :allowed_pattern
|
9
|
+
|
10
|
+
def initialize(name, definition, parameter)
|
11
|
+
@name = name
|
12
|
+
@definition = definition
|
13
|
+
@parameter = parameter
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_is_valid
|
19
|
+
return true unless @definition.key?(KEY)
|
20
|
+
invalid_values.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def invalid_values
|
24
|
+
values = build_values(@definition, @parameter)
|
25
|
+
values.reject { |value| value.to_s.match(%r{#{@definition[KEY]}}) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_error
|
29
|
+
"#{@name}:#{invalid_values} does not match #{KEY}:#{@definition[KEY]}"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative 'value_validator'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
module SparkleFormation
|
5
|
+
module CompileTime
|
6
|
+
class AllowedValuesValidator < ValueValidator
|
7
|
+
|
8
|
+
KEY = :allowed_values
|
9
|
+
|
10
|
+
def initialize(name, definition, parameter)
|
11
|
+
@name = name
|
12
|
+
@definition = definition
|
13
|
+
@parameter = parameter
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_is_valid
|
19
|
+
return true unless @definition.key?(KEY)
|
20
|
+
invalid_values.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def invalid_values
|
24
|
+
values = build_values(@definition, @parameter)
|
25
|
+
values.reject do |value|
|
26
|
+
@definition[KEY].any? { |allowed_value| allowed_value.to_s == value.to_s}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_error
|
31
|
+
"#{@name}:#{invalid_values} is not in #{KEY}:#{@definition[KEY]}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'value_validator'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
module SparkleFormation
|
5
|
+
module CompileTime
|
6
|
+
class DefinitionsValidator
|
7
|
+
|
8
|
+
VALID_TYPES = [:string, :number]
|
9
|
+
def initialize(definitions)
|
10
|
+
@definitions = definitions
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate
|
14
|
+
@definitions.each do|name, definition|
|
15
|
+
type = definition[:type]
|
16
|
+
raise ArgumentError.new "Unknown compile time parameter type: #{create_error(name, type)}" unless is_valid(type)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def is_valid(type)
|
23
|
+
VALID_TYPES.include? type
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_error(name, type)
|
27
|
+
"#{name}:#{type} valid types are #{VALID_TYPES}"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'value_validator'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
module SparkleFormation
|
5
|
+
module CompileTime
|
6
|
+
class EmptyValidator < ValueValidator
|
7
|
+
|
8
|
+
def initialize(name, definition, parameter)
|
9
|
+
@name = name
|
10
|
+
@definition = definition
|
11
|
+
@parameter = parameter
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def check_is_valid
|
17
|
+
!has_invalid_values?
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_invalid_values?
|
21
|
+
values = build_values(@definition, @parameter)
|
22
|
+
values.include?(nil) || values.include?('')
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_error
|
26
|
+
"#{@name} cannot contain empty parameters:#{@parameter.inspect}"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'value_validator'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
module SparkleFormation
|
5
|
+
module CompileTime
|
6
|
+
class MaxLengthValidator < ValueValidator
|
7
|
+
|
8
|
+
KEY = :max_length
|
9
|
+
|
10
|
+
def initialize(name, definition, parameter)
|
11
|
+
@name = name
|
12
|
+
@definition = definition
|
13
|
+
@parameter = parameter
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_is_valid
|
19
|
+
return true unless @definition[:type] == :string
|
20
|
+
return true unless @definition.key?(KEY)
|
21
|
+
invalid_values.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def invalid_values
|
25
|
+
values = build_values(@definition, @parameter)
|
26
|
+
values.select { |values| values.length > @definition[KEY].to_i }
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_error
|
30
|
+
"#{@name}:#{invalid_values} must not exceed #{KEY}:#{@definition[KEY]} characters"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'value_validator'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
module SparkleFormation
|
5
|
+
module CompileTime
|
6
|
+
class MaxSizeValidator < ValueValidator
|
7
|
+
|
8
|
+
KEY = :max_size
|
9
|
+
|
10
|
+
def initialize(name, definition, parameter)
|
11
|
+
@name = name
|
12
|
+
@definition = definition
|
13
|
+
@parameter = parameter
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_is_valid
|
19
|
+
return true unless @definition[:type] == :number
|
20
|
+
return true unless @definition.key?(KEY)
|
21
|
+
invalid_values.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def invalid_values
|
25
|
+
values = build_values(@definition, @parameter)
|
26
|
+
values.select { |value| value.to_f > @definition[KEY].to_f }
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_error
|
30
|
+
"#{@name}:#{invalid_values} must not be greater than #{KEY}:#{@definition[KEY]}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'value_validator'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
module SparkleFormation
|
5
|
+
module CompileTime
|
6
|
+
class MinLengthValidator < ValueValidator
|
7
|
+
|
8
|
+
KEY = :min_length
|
9
|
+
|
10
|
+
def initialize(name, definition, parameter)
|
11
|
+
@name = name
|
12
|
+
@definition = definition
|
13
|
+
@parameter = parameter
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_is_valid
|
19
|
+
return true unless @definition[:type] == :string
|
20
|
+
return true unless @definition.key?(KEY)
|
21
|
+
invalid_values.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def invalid_values
|
25
|
+
values = build_values(@definition, @parameter)
|
26
|
+
values.select { |value| value.length < @definition[KEY].to_i}
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_error
|
30
|
+
"#{@name}:#{invalid_values} must be at least #{KEY}:#{@definition[KEY]} characters"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|