stack_master 0.6.0 → 0.7.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/README.md +22 -0
- data/features/apply.feature +1 -1
- data/features/apply_with_s3.feature +106 -0
- data/features/step_definitions/stack_steps.rb +5 -0
- data/features/support/env.rb +1 -0
- data/lib/stack_master.rb +78 -58
- data/lib/stack_master/aws_driver/s3.rb +66 -0
- data/lib/stack_master/cli.rb +1 -0
- data/lib/stack_master/commands/apply.rb +52 -5
- data/lib/stack_master/commands/init.rb +2 -0
- data/lib/stack_master/commands/list_stacks.rb +2 -0
- data/lib/stack_master/commands/outputs.rb +2 -0
- data/lib/stack_master/commands/status.rb +3 -0
- data/lib/stack_master/parameter_resolver.rb +1 -1
- data/lib/stack_master/parameter_resolvers/secret.rb +2 -0
- data/lib/stack_master/stack.rb +20 -13
- data/lib/stack_master/stack_definition.rb +63 -13
- data/lib/stack_master/stack_differ.rb +2 -0
- data/lib/stack_master/stack_events/fetcher.rb +1 -1
- data/lib/stack_master/stack_events/presenter.rb +1 -1
- data/lib/stack_master/stack_events/streamer.rb +1 -1
- data/lib/stack_master/template_compiler.rb +3 -1
- data/lib/stack_master/template_compilers/cfndsl.rb +4 -2
- data/lib/stack_master/template_compilers/json.rb +4 -0
- data/lib/stack_master/template_compilers/sparkle_formation.rb +5 -0
- data/lib/stack_master/template_compilers/yaml.rb +4 -0
- data/lib/stack_master/test_driver/cloud_formation.rb +50 -36
- data/lib/stack_master/test_driver/s3.rb +34 -0
- data/lib/stack_master/testing.rb +1 -0
- data/lib/stack_master/utils.rb +19 -0
- data/lib/stack_master/version.rb +1 -1
- data/spec/fixtures/stack_master.yml +4 -1
- data/spec/stack_master/aws_driver/s3_spec.rb +130 -0
- data/spec/stack_master/commands/apply_spec.rb +26 -0
- data/spec/stack_master/config_spec.rb +8 -1
- data/spec/stack_master/parameter_resolver_spec.rb +5 -0
- data/spec/stack_master/sparkle_formation/user_data_file_spec.rb +2 -0
- data/spec/stack_master/stack_events/presenter_spec.rb +1 -1
- data/spec/stack_master/stack_spec.rb +23 -5
- data/spec/stack_master/template_compiler_spec.rb +1 -0
- data/spec/stack_master/template_compilers/cfndsl_spec.rb +2 -0
- data/spec/stack_master/test_driver/s3_spec.rb +17 -0
- data/stack_master.gemspec +0 -1
- metadata +10 -16
@@ -42,7 +42,7 @@ module StackMaster
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def resolve_parameter_value(key, parameter_value)
|
45
|
-
return parameter_value.to_s if Numeric === parameter_value
|
45
|
+
return parameter_value.to_s if Numeric === parameter_value || parameter_value == true || parameter_value == false
|
46
46
|
return parameter_value.join(',') if Array === parameter_value
|
47
47
|
return parameter_value unless Hash === parameter_value
|
48
48
|
validate_parameter_value!(key, parameter_value)
|
data/lib/stack_master/stack.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
module StackMaster
|
2
2
|
class Stack
|
3
3
|
MAX_TEMPLATE_SIZE = 51200
|
4
|
+
MAX_S3_TEMPLATE_SIZE = 460800
|
4
5
|
|
5
|
-
|
6
|
+
attr_reader :stack_name,
|
7
|
+
:region,
|
8
|
+
:stack_id,
|
9
|
+
:stack_status,
|
10
|
+
:parameters,
|
11
|
+
:template_body,
|
12
|
+
:notification_arns,
|
13
|
+
:outputs,
|
14
|
+
:stack_policy_body,
|
15
|
+
:tags,
|
16
|
+
:files
|
6
17
|
|
7
|
-
|
8
|
-
attribute :region, String
|
9
|
-
attribute :stack_id, String
|
10
|
-
attribute :stack_status, String
|
11
|
-
attribute :parameters, Hash
|
12
|
-
attribute :template_body, String
|
13
|
-
attribute :notification_arns, Array[String]
|
14
|
-
attribute :outputs, Array
|
15
|
-
attribute :stack_policy_body, String
|
16
|
-
attribute :tags, Hash
|
18
|
+
include Utils::Initializable
|
17
19
|
|
18
20
|
def template_hash
|
19
21
|
if template_body
|
@@ -87,8 +89,13 @@ module StackMaster
|
|
87
89
|
stack_policy_body: stack_policy_body)
|
88
90
|
end
|
89
91
|
|
90
|
-
def
|
91
|
-
|
92
|
+
def max_template_size(use_s3)
|
93
|
+
return MAX_S3_TEMPLATE_SIZE if use_s3
|
94
|
+
MAX_TEMPLATE_SIZE
|
95
|
+
end
|
96
|
+
|
97
|
+
def too_big?(use_s3 = false)
|
98
|
+
maybe_compressed_template_body.size > max_template_size(use_s3)
|
92
99
|
end
|
93
100
|
|
94
101
|
def aws_parameters
|
@@ -1,34 +1,84 @@
|
|
1
1
|
module StackMaster
|
2
2
|
class StackDefinition
|
3
|
-
|
3
|
+
attr_accessor :region,
|
4
|
+
:stack_name,
|
5
|
+
:template,
|
6
|
+
:tags,
|
7
|
+
:notification_arns,
|
8
|
+
:base_dir,
|
9
|
+
:secret_file,
|
10
|
+
:stack_policy_file,
|
11
|
+
:additional_parameter_lookup_dirs,
|
12
|
+
:s3,
|
13
|
+
:files
|
4
14
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
+
include Utils::Initializable
|
16
|
+
|
17
|
+
def initialize(attributes = {})
|
18
|
+
@additional_parameter_lookup_dirs = []
|
19
|
+
@notification_arns = []
|
20
|
+
@s3 = {}
|
21
|
+
@files = []
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(other)
|
26
|
+
self.class === other &&
|
27
|
+
@region == other.region &&
|
28
|
+
@stack_name == other.stack_name &&
|
29
|
+
@template == other.template &&
|
30
|
+
@tags == other.tags &&
|
31
|
+
@notification_arns == other.notification_arns &&
|
32
|
+
@base_dir == other.base_dir &&
|
33
|
+
@secret_file == other.secret_file &&
|
34
|
+
@stack_policy_file == other.stack_policy_file &&
|
35
|
+
@additional_parameter_lookup_dirs == other.additional_parameter_lookup_dirs &&
|
36
|
+
@s3 == other.s3
|
37
|
+
end
|
38
|
+
|
39
|
+
def template_dir
|
40
|
+
File.join(base_dir, 'templates')
|
15
41
|
end
|
16
42
|
|
17
43
|
def template_file_path
|
18
|
-
File.join(
|
44
|
+
File.join(template_dir, template)
|
45
|
+
end
|
46
|
+
|
47
|
+
def files_dir
|
48
|
+
File.join(base_dir, 'files')
|
49
|
+
end
|
50
|
+
|
51
|
+
def s3_files
|
52
|
+
files.inject({}) do |hash, file|
|
53
|
+
path = File.join(files_dir, file)
|
54
|
+
hash[file] = {
|
55
|
+
path: path,
|
56
|
+
body: File.read(path)
|
57
|
+
}
|
58
|
+
hash
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def s3_template_file_name
|
63
|
+
Utils.change_extension(template, 'json')
|
19
64
|
end
|
20
65
|
|
21
66
|
def parameter_files
|
22
|
-
[ default_parameter_file_path, region_parameter_file_path ]
|
67
|
+
[ default_parameter_file_path, region_parameter_file_path, additional_parameter_lookup_file_paths ].flatten.compact
|
23
68
|
end
|
24
69
|
|
25
70
|
def stack_policy_file_path
|
26
71
|
File.join(base_dir, 'policies', stack_policy_file) if stack_policy_file
|
27
72
|
end
|
28
73
|
|
74
|
+
def s3_configured?
|
75
|
+
!s3.nil?
|
76
|
+
end
|
77
|
+
|
29
78
|
private
|
30
79
|
|
31
80
|
def additional_parameter_lookup_file_paths
|
81
|
+
return unless additional_parameter_lookup_dirs
|
32
82
|
additional_parameter_lookup_dirs.map do |a|
|
33
83
|
File.join(base_dir, 'parameters', a, "#{underscored_stack_name}.yml")
|
34
84
|
end
|
@@ -3,7 +3,9 @@ module StackMaster
|
|
3
3
|
TemplateCompilationFailed = Class.new(RuntimeError)
|
4
4
|
|
5
5
|
def self.compile(config, template_file_path)
|
6
|
-
template_compiler_for_file(template_file_path, config)
|
6
|
+
compiler = template_compiler_for_file(template_file_path, config)
|
7
|
+
compiler.require_dependencies
|
8
|
+
compiler.compile(template_file_path)
|
7
9
|
rescue
|
8
10
|
raise TemplateCompilationFailed.new("Failed to compile #{template_file_path}.")
|
9
11
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module StackMaster::TemplateCompilers
|
2
2
|
class Cfndsl
|
3
|
+
def self.require_dependencies
|
4
|
+
require 'cfndsl'
|
5
|
+
end
|
3
6
|
|
4
7
|
def self.compile(template_file_path)
|
5
|
-
|
6
|
-
CfnDsl.eval_file_with_extras(template_file_path).to_json
|
8
|
+
::CfnDsl.eval_file_with_extras(template_file_path).to_json
|
7
9
|
end
|
8
10
|
|
9
11
|
StackMaster::TemplateCompiler.register(:cfndsl, self)
|
@@ -3,6 +3,10 @@ module StackMaster::TemplateCompilers
|
|
3
3
|
MAX_TEMPLATE_SIZE = 51200
|
4
4
|
private_constant :MAX_TEMPLATE_SIZE
|
5
5
|
|
6
|
+
def self.require_dependencies
|
7
|
+
require 'json'
|
8
|
+
end
|
9
|
+
|
6
10
|
def self.compile(template_file_path)
|
7
11
|
template_body = File.read(template_file_path)
|
8
12
|
if template_body.size > MAX_TEMPLATE_SIZE
|
@@ -1,5 +1,10 @@
|
|
1
1
|
module StackMaster::TemplateCompilers
|
2
2
|
class SparkleFormation
|
3
|
+
def self.require_dependencies
|
4
|
+
require 'sparkle_formation'
|
5
|
+
require 'stack_master/sparkle_formation/user_data_file'
|
6
|
+
end
|
7
|
+
|
3
8
|
def self.compile(template_file_path)
|
4
9
|
::SparkleFormation.sparkle_path = File.dirname(template_file_path)
|
5
10
|
JSON.pretty_generate(::SparkleFormation.compile(template_file_path))
|
@@ -1,48 +1,62 @@
|
|
1
1
|
module StackMaster
|
2
2
|
module TestDriver
|
3
3
|
class Stack
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
4
|
+
attr_reader :stack_id,
|
5
|
+
:stack_name,
|
6
|
+
:description,
|
7
|
+
:parameters,
|
8
|
+
:creation_time,
|
9
|
+
:last_update_time,
|
10
|
+
:stack_status,
|
11
|
+
:stack_status_reason,
|
12
|
+
:disable_rollback,
|
13
|
+
:notification_arns,
|
14
|
+
:timeout_in_minutes,
|
15
|
+
:capabilities,
|
16
|
+
:outputs,
|
17
|
+
:tags
|
18
|
+
|
19
|
+
include Utils::Initializable
|
20
|
+
|
21
|
+
def parameters
|
22
|
+
@parameters.map do |hash|
|
23
|
+
OpenStruct.new(parameter_key: hash[:parameter_key],
|
24
|
+
parameter_value: hash[:parameter_value])
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
21
29
|
class StackEvent
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
attr_reader :stack_id,
|
31
|
+
:event_id,
|
32
|
+
:stack_name,
|
33
|
+
:logical_resource_id,
|
34
|
+
:physical_resource_id,
|
35
|
+
:resource_type,
|
36
|
+
:timestamp,
|
37
|
+
:resource_status,
|
38
|
+
:resource_status_reason,
|
39
|
+
:resource_properties
|
40
|
+
|
41
|
+
include Utils::Initializable
|
42
|
+
|
43
|
+
def timestamp
|
44
|
+
Time.parse(@timestamp) if @timestamp
|
45
|
+
end
|
33
46
|
end
|
34
47
|
|
35
48
|
class StackResource
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
49
|
+
attr_reader :stack_name,
|
50
|
+
:stack_id,
|
51
|
+
:logical_resource_id,
|
52
|
+
:physical_resource_id,
|
53
|
+
:resource_type,
|
54
|
+
:timestamp,
|
55
|
+
:resource_status,
|
56
|
+
:resource_status_reason,
|
57
|
+
:description
|
58
|
+
|
59
|
+
include Utils::Initializable
|
46
60
|
end
|
47
61
|
|
48
62
|
class CloudFormation
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module StackMaster
|
2
|
+
module TestDriver
|
3
|
+
class S3
|
4
|
+
def initialize
|
5
|
+
reset
|
6
|
+
end
|
7
|
+
|
8
|
+
def set_region(_)
|
9
|
+
end
|
10
|
+
|
11
|
+
def reset
|
12
|
+
@files = Hash.new { |hash, key| hash[key] = Hash.new }
|
13
|
+
end
|
14
|
+
|
15
|
+
def upload_files(bucket: nil, prefix: nil, region: nil, files: {})
|
16
|
+
return if files.empty?
|
17
|
+
|
18
|
+
files.each do |template, file|
|
19
|
+
object_key = [prefix, template].compact.join('/')
|
20
|
+
@files[bucket][object_key] = file[:body]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def url(bucket:, prefix:, region:, template:)
|
25
|
+
["https://s3-#{region}.amazonaws.com", bucket, prefix, template].compact.join('/')
|
26
|
+
end
|
27
|
+
|
28
|
+
# test only method
|
29
|
+
def find_file(bucket:, object_key:)
|
30
|
+
@files[bucket][object_key]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/stack_master/testing.rb
CHANGED
data/lib/stack_master/utils.rb
CHANGED
@@ -1,7 +1,26 @@
|
|
1
1
|
module StackMaster
|
2
2
|
module Utils
|
3
|
+
module Initializable
|
4
|
+
def initialize(attributes = {})
|
5
|
+
self.attributes = attributes
|
6
|
+
end
|
7
|
+
|
8
|
+
def attributes=(attributes)
|
9
|
+
attributes.each do |k, v|
|
10
|
+
instance_variable_set("@#{k}", v)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
3
15
|
extend self
|
4
16
|
|
17
|
+
def change_extension(file_name, extension)
|
18
|
+
[
|
19
|
+
File.basename(file_name, '.*'),
|
20
|
+
extension
|
21
|
+
].join('.')
|
22
|
+
end
|
23
|
+
|
5
24
|
def hash_to_aws_parameters(params)
|
6
25
|
params.inject([]) do |params, (key, value)|
|
7
26
|
params << { parameter_key: key, parameter_value: value }
|