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
@@ -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
|
data/lib/stack_master/stack.rb
CHANGED
@@ -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
|
-
|
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:
|
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,
|
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,
|
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[
|
10
|
-
::SparkleFormation.sparkle_path = File.expand_path(compiler_options[
|
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
|
-
|
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)
|
@@ -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
|
data/lib/stack_master/version.rb
CHANGED
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`.
|