stack_master 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|