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.
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
@@ -0,0 +1,36 @@
1
+ require_relative 'value_validator'
2
+
3
+ module StackMaster
4
+ module SparkleFormation
5
+ module CompileTime
6
+ class MinSizeValidator < ValueValidator
7
+
8
+ KEY = :min_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 lesser than #{KEY}:#{@definition[KEY]}"
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'value_validator'
2
+
3
+ module StackMaster
4
+ module SparkleFormation
5
+ module CompileTime
6
+ class NumberValidator < 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
+ return true unless @definition[:type] == :number
18
+ invalid_values.empty?
19
+ end
20
+
21
+ def invalid_values
22
+ values = build_values(@definition, @parameter)
23
+ values.reject do |value|
24
+ value.is_a?(Numeric) || value.is_a?(String) && value.to_s =~ /^(\d+)(\.?(\d+))?$/
25
+ end
26
+ end
27
+
28
+ def create_error
29
+ "#{@name}:#{invalid_values} are not Numbers"
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'value_validator_factory'
2
+
3
+ module StackMaster
4
+ module SparkleFormation
5
+ module CompileTime
6
+ class ParametersValidator
7
+
8
+ def initialize(definitions, parameters)
9
+ @definitions = definitions
10
+ @parameters = parameters
11
+ end
12
+
13
+ def validate
14
+ @definitions.each do |name, definition|
15
+ parameter = @parameters[name.to_s.camelize]
16
+ factory = ValueValidatorFactory.new(name, definition, parameter)
17
+ value_validators = factory.build
18
+ value_validators.each do |validator|
19
+ validator.validate
20
+ raise ArgumentError.new "Invalid compile time parameter: #{validator.error}" unless validator.is_valid
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ require_relative 'value_builder'
2
+
3
+ module StackMaster
4
+ module SparkleFormation
5
+ module CompileTime
6
+ class StateBuilder
7
+
8
+ def initialize(definitions, parameters)
9
+ @definitions = definitions
10
+ @parameters = parameters
11
+ end
12
+
13
+ def build
14
+ state = {}
15
+ @definitions.each do |name, definition|
16
+ parameter_key = name.to_s.camelize
17
+ parameter = @parameters[parameter_key]
18
+ state[name] = create_value(definition, parameter)
19
+ end
20
+ state
21
+ end
22
+
23
+ private
24
+
25
+ def create_value(definition, parameter)
26
+ ValueBuilder.new(definition, parameter).build
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'value_validator'
2
+
3
+ module StackMaster
4
+ module SparkleFormation
5
+ module CompileTime
6
+ class StringValidator < 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
+ return true unless @definition[:type] == :string
18
+ invalid_values.empty?
19
+ end
20
+
21
+ def invalid_values
22
+ values = build_values(@definition, @parameter)
23
+ values.reject { |value| value.is_a?(String)}
24
+ end
25
+
26
+ def create_error
27
+ "#{@name}:#{invalid_values} are not Strings"
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ module StackMaster
2
+ module SparkleFormation
3
+ module CompileTime
4
+ class ValueBuilder
5
+
6
+ def initialize(definition, parameter)
7
+ @definition = definition
8
+ @parameter = parameter
9
+ end
10
+
11
+ def build
12
+ parameter_or_default
13
+ convert_strings_to_array
14
+ convert_strings_to_numbers
15
+ @value
16
+ end
17
+
18
+ private
19
+
20
+ def parameter_or_default
21
+ @value = @parameter.nil? ? @definition[:default] : @parameter
22
+ end
23
+
24
+ def convert_strings_to_array
25
+ if @definition[:multiple] && @value.is_a?(String)
26
+ @value = @value.split(',').map(&:strip)
27
+ end
28
+ end
29
+
30
+ def convert_strings_to_numbers
31
+ if @definition[:type] == :number
32
+ @value = @value.to_f if @value.is_a?(String)
33
+ @value = @value.map { |item| item.is_a?(String) ? item.to_f : item } if @value.is_a?(Array)
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ module StackMaster
2
+ module SparkleFormation
3
+ module CompileTime
4
+ class ValueValidator
5
+
6
+ attr_reader :is_valid, :error
7
+
8
+ def validate
9
+ @is_valid = check_is_valid
10
+ @error = create_error unless @is_valid
11
+ end
12
+
13
+ protected
14
+
15
+ def check_is_valid
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def create_error
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def build_values(definition, parameter)
24
+ parameter_or_default = parameter.nil? ? definition[:default] : parameter
25
+ convert_to_array(definition, parameter_or_default)
26
+ end
27
+
28
+ private
29
+
30
+ def convert_to_array(definition, parameter)
31
+ if definition[:multiple] && parameter.is_a?(String)
32
+ return parameter.split(',').map(&:strip)
33
+ end
34
+ parameter.is_a?(Array) ? parameter : [parameter]
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'empty_validator'
2
+ require_relative 'string_validator'
3
+ require_relative 'number_validator'
4
+ require_relative 'allowed_values_validator'
5
+ require_relative 'allowed_pattern_validator'
6
+ require_relative 'max_length_validator'
7
+ require_relative 'min_length_validator'
8
+ require_relative 'max_size_validator'
9
+ require_relative 'min_size_validator'
10
+
11
+ module StackMaster
12
+ module SparkleFormation
13
+ module CompileTime
14
+ class ValueValidatorFactory
15
+
16
+ VALIDATORS_TYPES = [
17
+ EmptyValidator,
18
+ StringValidator,
19
+ NumberValidator,
20
+ AllowedValuesValidator,
21
+ AllowedPatternValidator,
22
+ MaxLengthValidator,
23
+ MinLengthValidator,
24
+ MaxSizeValidator,
25
+ MinSizeValidator
26
+ ]
27
+
28
+ def initialize(name, definition, parameter)
29
+ @name = name
30
+ @definition = definition
31
+ @parameter = parameter
32
+ end
33
+
34
+ def build
35
+ VALIDATORS_TYPES.map { |validator| validator.new(@name, @definition, @parameter)}
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -63,16 +63,17 @@ module StackMaster
63
63
 
64
64
  def self.generate(stack_definition, config)
65
65
  parameter_hash = ParameterLoader.load(stack_definition.parameter_files)
66
- template_body = TemplateCompiler.compile(config, stack_definition.template_file_path, stack_definition.compiler_options)
66
+ template_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:template_parameters])
67
+ compile_time_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:compile_time_parameters])
68
+ template_body = TemplateCompiler.compile(config, stack_definition.template_file_path, compile_time_parameters,stack_definition.compiler_options)
67
69
  template_format = TemplateUtils.identify_template_format(template_body)
68
- parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash)
69
70
  stack_policy_body = if stack_definition.stack_policy_file_path
70
71
  File.read(stack_definition.stack_policy_file_path)
71
72
  end
72
73
  new(region: stack_definition.region,
73
74
  stack_name: stack_definition.stack_name,
74
75
  tags: stack_definition.tags,
75
- parameters: parameters,
76
+ parameters: template_parameters,
76
77
  template_body: template_body,
77
78
  template_format: template_format,
78
79
  role_arn: stack_definition.role_arn,
@@ -2,10 +2,10 @@ module StackMaster
2
2
  class TemplateCompiler
3
3
  TemplateCompilationFailed = Class.new(RuntimeError)
4
4
 
5
- def self.compile(config, template_file_path, compiler_options = {})
5
+ def self.compile(config, template_file_path, compile_time_parameters, compiler_options = {})
6
6
  compiler = template_compiler_for_file(template_file_path, config)
7
7
  compiler.require_dependencies
8
- compiler.compile(template_file_path, compiler_options)
8
+ compiler.compile(template_file_path, compile_time_parameters, compiler_options)
9
9
  rescue
10
10
  raise TemplateCompilationFailed.new("Failed to compile #{template_file_path}.")
11
11
  end
@@ -4,7 +4,7 @@ module StackMaster::TemplateCompilers
4
4
  require 'cfndsl'
5
5
  end
6
6
 
7
- def self.compile(template_file_path, compiler_options = {})
7
+ def self.compile(template_file_path, _compile_time_parameters, _compiler_options = {})
8
8
  ::CfnDsl.eval_file_with_extras(template_file_path).to_json
9
9
  end
10
10
 
@@ -7,7 +7,7 @@ module StackMaster::TemplateCompilers
7
7
  require 'json'
8
8
  end
9
9
 
10
- def self.compile(template_file_path, compiler_options = {})
10
+ def self.compile(template_file_path, _compile_time_parameters, _compiler_options = {})
11
11
  template_body = File.read(template_file_path)
12
12
  if template_body.size > MAX_TEMPLATE_SIZE
13
13
  # Parse the json and rewrite compressed
@@ -1,18 +1,47 @@
1
+ require 'stack_master/sparkle_formation/compile_time/parameters_validator'
2
+ require 'stack_master/sparkle_formation/compile_time/definitions_validator'
3
+ require 'stack_master/sparkle_formation/compile_time/state_builder'
4
+
1
5
  module StackMaster::TemplateCompilers
2
6
  class SparkleFormation
7
+
8
+ CompileTime = StackMaster::SparkleFormation::CompileTime
9
+
3
10
  def self.require_dependencies
4
11
  require 'sparkle_formation'
5
12
  require 'stack_master/sparkle_formation/template_file'
6
13
  end
7
14
 
8
- def self.compile(template_file_path, compiler_options = {})
9
- if compiler_options["sparkle_path"]
10
- ::SparkleFormation.sparkle_path = File.expand_path(compiler_options["sparkle_path"])
15
+ def self.compile(template_file_path, compile_time_parameters, compiler_options = {})
16
+ if compiler_options['sparkle_path']
17
+ ::SparkleFormation.sparkle_path = File.expand_path(compiler_options['sparkle_path'])
11
18
  else
12
19
  ::SparkleFormation.sparkle_path = File.dirname(template_file_path)
13
20
  end
21
+ sparkle_template = ::SparkleFormation.compile(template_file_path, :sparkle)
22
+ definitions = sparkle_template.parameters
23
+ validate_definitions(definitions)
24
+ validate_parameters(definitions, compile_time_parameters)
25
+
26
+ sparkle_template.compile_time_parameter_setter do
27
+ sparkle_template.compile_state = create_state(definitions, compile_time_parameters)
28
+ end
29
+
30
+ JSON.pretty_generate(sparkle_template)
31
+ end
32
+
33
+ private
34
+
35
+ def self.validate_definitions(definitions)
36
+ CompileTime::DefinitionsValidator.new(definitions).validate
37
+ end
38
+
39
+ def self.validate_parameters(definitions, compile_time_parameters)
40
+ CompileTime::ParametersValidator.new(definitions, compile_time_parameters).validate
41
+ end
14
42
 
15
- JSON.pretty_generate(::SparkleFormation.compile(template_file_path))
43
+ def self.create_state(definitions, compile_time_parameters)
44
+ CompileTime::StateBuilder.new(definitions, compile_time_parameters).build
16
45
  end
17
46
 
18
47
  StackMaster::TemplateCompiler.register(:sparkle_formation, self)
@@ -5,7 +5,7 @@ module StackMaster::TemplateCompilers
5
5
  require 'json'
6
6
  end
7
7
 
8
- def self.compile(template_file_path, compiler_options = {})
8
+ def self.compile(template_file_path, _compile_time_parameters, _compiler_options = {})
9
9
  File.read(template_file_path)
10
10
  end
11
11
 
@@ -10,8 +10,11 @@ module StackMaster
10
10
  end
11
11
 
12
12
  def perform
13
+ parameter_hash = ParameterLoader.load(@stack_definition.parameter_files)
14
+ compile_time_parameters = ParameterResolver.resolve(@config, @stack_definition, parameter_hash[:compile_time_parameters])
15
+
13
16
  StackMaster.stdout.print "#{@stack_definition.stack_name}: "
14
- template_body = TemplateCompiler.compile(@config, @stack_definition.template_file_path, @stack_definition.compiler_options)
17
+ template_body = TemplateCompiler.compile(@config, @stack_definition.template_file_path, compile_time_parameters, @stack_definition.compiler_options)
15
18
  cf.validate_template(template_body: TemplateUtils.maybe_compressed_template_body(template_body))
16
19
  StackMaster.stdout.puts "valid"
17
20
  true
@@ -1,3 +1,3 @@
1
1
  module StackMaster
2
- VERSION = "0.17.0"
2
+ VERSION = "0.18.0"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'stack_master'
2
2
  require 'timecop'
3
3
  require 'pry'
4
+
5
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
6
+
4
7
  Aws.config[:stub_responses] = true
5
8
  # This file was generated by the `rspec --init` command. Conventionally, all
6
9
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.