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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -5
  3. data/README.md +15 -0
  4. data/features/apply.feature +0 -1
  5. data/features/apply_with_compile_time_parameters.feature +93 -0
  6. data/lib/stack_master/parameter_loader.rb +41 -12
  7. data/lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb +35 -0
  8. data/lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb +37 -0
  9. data/lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb +33 -0
  10. data/lib/stack_master/sparkle_formation/compile_time/empty_validator.rb +32 -0
  11. data/lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb +36 -0
  12. data/lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb +36 -0
  13. data/lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb +36 -0
  14. data/lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb +36 -0
  15. data/lib/stack_master/sparkle_formation/compile_time/number_validator.rb +35 -0
  16. data/lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb +27 -0
  17. data/lib/stack_master/sparkle_formation/compile_time/state_builder.rb +32 -0
  18. data/lib/stack_master/sparkle_formation/compile_time/string_validator.rb +33 -0
  19. data/lib/stack_master/sparkle_formation/compile_time/value_builder.rb +40 -0
  20. data/lib/stack_master/sparkle_formation/compile_time/value_validator.rb +40 -0
  21. data/lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb +41 -0
  22. data/lib/stack_master/stack.rb +4 -3
  23. data/lib/stack_master/template_compiler.rb +2 -2
  24. data/lib/stack_master/template_compilers/cfndsl.rb +1 -1
  25. data/lib/stack_master/template_compilers/json.rb +1 -1
  26. data/lib/stack_master/template_compilers/sparkle_formation.rb +33 -4
  27. data/lib/stack_master/template_compilers/yaml.rb +1 -1
  28. data/lib/stack_master/validator.rb +4 -1
  29. data/lib/stack_master/version.rb +1 -1
  30. data/spec/spec_helper.rb +3 -0
  31. data/spec/stack_master/parameter_loader_spec.rb +65 -53
  32. data/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb +47 -0
  33. data/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb +47 -0
  34. data/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb +36 -0
  35. data/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb +47 -0
  36. data/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb +37 -0
  37. data/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb +27 -0
  38. data/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb +36 -0
  39. data/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb +28 -0
  40. data/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb +41 -0
  41. data/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb +65 -0
  42. data/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb +28 -0
  43. data/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb +35 -0
  44. data/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb +52 -0
  45. data/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb +40 -0
  46. data/spec/stack_master/stack_spec.rb +15 -13
  47. data/spec/stack_master/template_compiler_spec.rb +7 -6
  48. data/spec/stack_master/template_compilers/cfndsl_spec.rb +4 -1
  49. data/spec/stack_master/template_compilers/json_spec.rb +4 -1
  50. data/spec/stack_master/template_compilers/sparkle_formation_spec.rb +53 -9
  51. data/spec/stack_master/template_compilers/yaml_spec.rb +4 -1
  52. data/spec/stack_master/validator_spec.rb +10 -6
  53. data/spec/support/gemfiles/Gemfile.activesupport-4.0.0 +5 -0
  54. data/spec/support/validator_spec.rb +23 -0
  55. data/stack_master.gemspec +1 -1
  56. metadata +55 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8db962bf4169a452e81cee1d7ece124096742f13
4
- data.tar.gz: 865423915902223abcf444b3431b8db49c6011a7
3
+ metadata.gz: ce12082b568677adbd824876ec9bdc2c64e399f8
4
+ data.tar.gz: 854fe4aa23253b1ae5eaec64b1f8ac6fbef97ac1
5
5
  SHA512:
6
- metadata.gz: 79fa18d43b6e1b2db51f0376f481793b6604476cf4311e21505a3c9507569fa1834b5f036a782f679aa14cd5d7fbb2ca8811d846fed95a5e710b4d88b3893dd3
7
- data.tar.gz: 1c9b305fcfae1a2705ade052e48f070468dcfe33852c2cc54ee153b3d6e9286e449f9d66c9d10e2cba2d2d54e4c65cf440af766366e03cae2e3735cf1da6299c
6
+ metadata.gz: 598cd004f968afdc315d4d5132e63d5c430180102b7d0ea6299163ce143ff0d5682dd0c13d84bd35e3044c981250750539624793f132bc8d9aed271475adf5b2
7
+ data.tar.gz: e395e0c8ea148cac6a14c82680463539d4143751e2f673323e6e8b7b221dcdaea6c3f2d1853fdb31afa773b774d33f4a55adf7d3cdaf23d3d528af2f64f71d79
data/.travis.yml CHANGED
@@ -1,9 +1,11 @@
1
1
  language: ruby
2
- rvm:
3
- - 2.1
4
- - 2.2
5
- - 2.3.1
6
- - 2.4.0
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
@@ -304,7 +304,6 @@ Feature: Apply command
304
304
  | Parameters diff: No changes |
305
305
  Then the exit status should be 0
306
306
 
307
-
308
307
  Scenario: Create a stack using a stack output resolver
309
308
  Given a file named "parameters/myapp_web.yml" with:
310
309
  """
@@ -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 "Searching for parameter files..."
5
- parameter_files.reduce({}) do |hash, file_name|
6
- parameters = if File.exists?(file_name)
7
- StackMaster.debug " #{file_name} found"
8
- YAML.load(File.read(file_name)) || {}
9
- else
10
- StackMaster.debug " #{file_name} not found"
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