stack_master 0.10.1 → 0.10.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 912d6ca4f6983f7596e2f19064a3a095b766dcea
4
- data.tar.gz: 2d10bee6f5db987640f7ae0bdf53749f7baa7030
3
+ metadata.gz: dac9ea54e5fb5f551c15e0d077816eb62b79cb7a
4
+ data.tar.gz: f9e58ade11de8c75902ffc8ed83a03d623b02a83
5
5
  SHA512:
6
- metadata.gz: 290c0443cc24477a349f8c1256ff915652ab99b233b7013d08316656eab94df4b8e87f8299133ff9e1b804c46f1b1a21f56ead4223678d81f1686614302400b0
7
- data.tar.gz: 4105297fb4bd6c6535bb0cb143709406dec991b3dc9ebf7fc20d6e332b8f568178db5ce36932f756235947f024c5518e8319f896b4b64f28a3df600c74250c70
6
+ metadata.gz: 18f4ad8e75146c81a63b33aade1e97ac14d133863def43e62f78e969120122eeba7ec33f90253d7582904443d9cedcab444d54c57e43637e5800981ff0a4000d
7
+ data.tar.gz: 311a35d9e1976033c4ab45a588199596b8be674af0669abd0dc27c77ec7f17f9a28b09d050ab0586b72fc578c02afab99aec9acf5112f6ac57fdbe9df988e574
@@ -24,6 +24,7 @@ module StackMaster
24
24
  autoload :ResolverArray, 'stack_master/resolver_array'
25
25
  autoload :Resolver, 'stack_master/resolver_array'
26
26
  autoload :Utils, 'stack_master/utils'
27
+ autoload :TemplateUtils, 'stack_master/template_utils'
27
28
  autoload :Config, 'stack_master/config'
28
29
  autoload :PagedResponseAccumulator, 'stack_master/paged_response_accumulator'
29
30
  autoload :StackDefinition, 'stack_master/stack_definition'
@@ -103,7 +103,7 @@ module StackMaster
103
103
  if use_s3?
104
104
  s3.url(bucket: @s3_config['bucket'], prefix: @s3_config['prefix'], region: @s3_config['region'], template: @stack_definition.s3_template_file_name)
105
105
  else
106
- proposed_stack.maybe_compressed_template_body
106
+ proposed_stack.template
107
107
  end
108
108
  end
109
109
 
@@ -112,7 +112,7 @@ module StackMaster
112
112
  @stack_definition.s3_files.tap do |files|
113
113
  files[@stack_definition.s3_template_file_name] = {
114
114
  path: @stack_definition.template_file_path,
115
- body: proposed_stack.maybe_compressed_template_body
115
+ body: proposed_stack.template
116
116
  }
117
117
  end
118
118
  end
@@ -1,8 +1,5 @@
1
1
  module StackMaster
2
2
  class Stack
3
- MAX_TEMPLATE_SIZE = 51200
4
- MAX_S3_TEMPLATE_SIZE = 460800
5
-
6
3
  attr_reader :stack_name,
7
4
  :region,
8
5
  :stack_id,
@@ -18,25 +15,8 @@ module StackMaster
18
15
 
19
16
  include Utils::Initializable
20
17
 
21
- def template_hash
22
- return unless template_body
23
- @template_hash ||= case template_format
24
- when :json
25
- JSON.parse(template_body)
26
- when :yaml
27
- YAML.load(template_body)
28
- end
29
- end
30
-
31
- def maybe_compressed_template_body
32
- # Do not compress the template if it's not JSON because parsing YAML as a hash ignores
33
- # CloudFormation-specific tags such as !Ref
34
- return template_body if template_body.size <= MAX_TEMPLATE_SIZE || template_format != :json
35
- @compressed_template_body ||= JSON.dump(template_hash)
36
- end
37
-
38
18
  def template_default_parameters
39
- template_hash.fetch('Parameters', {}).inject({}) do |result, (parameter_name, description)|
19
+ TemplateUtils.template_hash(template).fetch('Parameters', {}).inject({}) do |result, (parameter_name, description)|
40
20
  result[parameter_name] = description['Default']
41
21
  result
42
22
  end
@@ -61,7 +41,7 @@ module StackMaster
61
41
  params_hash
62
42
  end
63
43
  template_body ||= cf.get_template(stack_name: stack_name).template_body
64
- template_format = identify_template_format(template_body)
44
+ template_format = TemplateUtils.identify_template_format(template_body)
65
45
  stack_policy_body ||= cf.get_stack_policy(stack_name: stack_name).stack_policy_body
66
46
  outputs = cf_stack.outputs
67
47
 
@@ -82,7 +62,7 @@ module StackMaster
82
62
  def self.generate(stack_definition, config)
83
63
  parameter_hash = ParameterLoader.load(stack_definition.parameter_files)
84
64
  template_body = TemplateCompiler.compile(config, stack_definition.template_file_path)
85
- template_format = identify_template_format(template_body)
65
+ template_format = TemplateUtils.identify_template_format(template_body)
86
66
  parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash)
87
67
  stack_policy_body = if stack_definition.stack_policy_file_path
88
68
  File.read(stack_definition.stack_policy_file_path)
@@ -97,19 +77,13 @@ module StackMaster
97
77
  stack_policy_body: stack_policy_body)
98
78
  end
99
79
 
100
- def self.identify_template_format(template_body)
101
- return :json if template_body =~ /^{/x # ignore leading whitespaces
102
- :yaml
103
- end
104
- private_class_method :identify_template_format
105
-
106
80
  def max_template_size(use_s3)
107
- return MAX_S3_TEMPLATE_SIZE if use_s3
108
- MAX_TEMPLATE_SIZE
81
+ return TemplateUtils::MAX_S3_TEMPLATE_SIZE if use_s3
82
+ TemplateUtils::MAX_TEMPLATE_SIZE
109
83
  end
110
84
 
111
85
  def too_big?(use_s3 = false)
112
- maybe_compressed_template_body.size > max_template_size(use_s3)
86
+ template.size > max_template_size(use_s3)
113
87
  end
114
88
 
115
89
  def aws_parameters
@@ -119,5 +93,9 @@ module StackMaster
119
93
  def aws_tags
120
94
  Utils.hash_to_aws_tags(tags)
121
95
  end
96
+
97
+ def template
98
+ @template ||= TemplateUtils.maybe_compressed_template_body(template_body)
99
+ end
122
100
  end
123
101
  end
@@ -15,7 +15,7 @@ module StackMaster
15
15
  def current_template
16
16
  return '' unless @current_stack
17
17
  return @current_stack.template_body unless @current_stack.template_format == :json
18
- JSON.pretty_generate(@current_stack.template_hash)
18
+ JSON.pretty_generate(TemplateUtils.template_hash(@current_stack.template_body))
19
19
  end
20
20
 
21
21
  def current_parameters
@@ -0,0 +1,31 @@
1
+ module StackMaster
2
+ module TemplateUtils
3
+ MAX_TEMPLATE_SIZE = 51200
4
+ MAX_S3_TEMPLATE_SIZE = 460800
5
+
6
+ extend self
7
+
8
+ def identify_template_format(template_body)
9
+ return :json if template_body =~ /^{/x # ignore leading whitespaces
10
+ :yaml
11
+ end
12
+
13
+ def template_hash(template_body=nil)
14
+ return unless template_body
15
+ template_format = identify_template_format(template_body)
16
+ case template_format
17
+ when :json
18
+ JSON.parse(template_body)
19
+ when :yaml
20
+ YAML.load(template_body)
21
+ end
22
+ end
23
+
24
+ def maybe_compressed_template_body(template_body)
25
+ # Do not compress the template if it's not JSON because parsing YAML as a hash ignores
26
+ # CloudFormation-specific tags such as !Ref
27
+ return template_body if template_body.size <= MAX_TEMPLATE_SIZE || identify_template_format(template_body) != :json
28
+ JSON.dump(template_hash(template_body))
29
+ end
30
+ end
31
+ end
@@ -11,8 +11,8 @@ module StackMaster
11
11
 
12
12
  def perform
13
13
  StackMaster.stdout.print "#{@stack_definition.stack_name}: "
14
- template_body = Stack.generate(@stack_definition, @config).maybe_compressed_template_body
15
- cf.validate_template(template_body: template_body)
14
+ template_body = TemplateCompiler.compile(@config, @stack_definition.template_file_path)
15
+ cf.validate_template(template_body: TemplateUtils.maybe_compressed_template_body(template_body))
16
16
  StackMaster.stdout.puts "valid"
17
17
  true
18
18
  rescue Aws::CloudFormation::Errors::ValidationError => e
@@ -1,3 +1,3 @@
1
1
  module StackMaster
2
- VERSION = "0.10.1"
2
+ VERSION = "0.10.2"
3
3
  end
@@ -0,0 +1,3 @@
1
+ param_1: 'hello'
2
+ param_2:
3
+ secret: world
@@ -32,6 +32,8 @@ stacks:
32
32
  - test_arn_2
33
33
  myapp_web:
34
34
  template: myapp_web.rb
35
+ myapp_vpc_with_secrets:
36
+ template: myapp_vpc.json
35
37
  ap-southeast-2:
36
38
  myapp_vpc:
37
39
  template: myapp_vpc.rb
@@ -17,8 +17,8 @@ RSpec.describe StackMaster::Commands::Status do
17
17
  end
18
18
 
19
19
  context "some parameters are different" do
20
- let(:stack1) { double(:stack1, template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') }
21
- let(:stack2) { double(:stack2, template_hash: {}, template_format: :json, parameters_with_defaults: {a: 2}, stack_status: 'CREATE_COMPLETE') }
20
+ let(:stack1) { double(:stack1, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') }
21
+ let(:stack2) { double(:stack2, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 2}, stack_status: 'CREATE_COMPLETE') }
22
22
  let(:proposed_stack1) { double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
23
23
  let(:proposed_stack2) { double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
24
24
 
@@ -29,8 +29,8 @@ RSpec.describe StackMaster::Commands::Status do
29
29
  end
30
30
 
31
31
  context "some templates are different" do
32
- let(:stack1) { double(:stack1, template_hash: {foo: 'bar'}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') }
33
- let(:stack2) { double(:stack2, template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'CREATE_COMPLETE') }
32
+ let(:stack1) { double(:stack1, template_body: '{"foo": "bar"}', template_hash: {foo: 'bar'}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') }
33
+ let(:stack2) { double(:stack2, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'CREATE_COMPLETE') }
34
34
  let(:proposed_stack1) { double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
35
35
  let(:proposed_stack2) { double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
36
36
 
@@ -53,12 +53,12 @@ RSpec.describe StackMaster::Config do
53
53
 
54
54
  it 'can filter by region only' do
55
55
  stacks = loaded_config.filter('us-east-1')
56
- expect(stacks.size).to eq 2
56
+ expect(stacks.size).to eq 3
57
57
  end
58
58
 
59
59
  it 'can return all stack definitions with no filters' do
60
60
  stacks = loaded_config.filter
61
- expect(stacks.size).to eq 4
61
+ expect(stacks.size).to eq 5
62
62
  end
63
63
  end
64
64
 
@@ -124,26 +124,6 @@ RSpec.describe StackMaster::Stack do
124
124
  end
125
125
  end
126
126
 
127
- describe "#maybe_compressed_template_body" do
128
- subject(:maybe_compressed_template_body) do
129
- stack.maybe_compressed_template_body
130
- end
131
- context "undersized json" do
132
- let(:stack) { described_class.new(template_body: '{ }' ) }
133
-
134
- it "leaves the json alone if it's not too large" do
135
- expect(maybe_compressed_template_body).to eq('{ }')
136
- end
137
- end
138
-
139
- context "oversized json" do
140
- let(:stack) { described_class.new(template_body: "{#{' ' * 60000}}", template_format: :json) }
141
- it "compresses the json when it's overly bulbous" do
142
- expect(maybe_compressed_template_body).to eq('{}')
143
- end
144
- end
145
- end
146
-
147
127
  describe '#too_big?' do
148
128
  let(:big_stack) { described_class.new(template_body: "{\"a\":\"#{'x' * 500000}\"}") }
149
129
  let(:medium_stack) { described_class.new(template_body: "{\"a\":\"#{'x' * 60000}\"}") }
@@ -0,0 +1,21 @@
1
+ RSpec.describe StackMaster::TemplateUtils do
2
+ describe "#maybe_compressed_template_body" do
3
+ subject(:maybe_compressed_template_body) do
4
+ described_class.maybe_compressed_template_body(template_body)
5
+ end
6
+ context "undersized json" do
7
+ let(:template_body) { '{ }' }
8
+
9
+ it "leaves the json alone if it's not too large" do
10
+ expect(maybe_compressed_template_body).to eq('{ }')
11
+ end
12
+ end
13
+
14
+ context "oversized json" do
15
+ let(:template_body) { "{#{' ' * 60000}}" }
16
+ it "compresses the json when it's overly bulbous" do
17
+ expect(maybe_compressed_template_body).to eq('{}')
18
+ end
19
+ end
20
+ end
21
+ end
@@ -2,10 +2,11 @@ RSpec.describe StackMaster::Validator do
2
2
 
3
3
  subject(:validator) { described_class.new(stack_definition, config) }
4
4
  let(:config) { StackMaster::Config.new({'stacks' => {}}, '/base_dir') }
5
+ let(:stack_name) { 'myapp_vpc' }
5
6
  let(:stack_definition) do
6
7
  StackMaster::StackDefinition.new(
7
8
  region: 'us-east-1',
8
- stack_name: 'myapp_vpc',
9
+ stack_name: stack_name,
9
10
  template: 'myapp_vpc.json',
10
11
  tags: { 'environment' => 'production' },
11
12
  base_dir: File.expand_path('spec/fixtures'),
@@ -34,6 +35,18 @@ RSpec.describe StackMaster::Validator do
34
35
  expect { validator.perform }.to output(/myapp_vpc: invalid/).to_stdout
35
36
  end
36
37
  end
38
+
39
+ context "validate is called from from a continuous integration system with no access to secrets" do
40
+ let(:stack_name) { 'myapp_vpc_with_secrets' }
41
+ let(:secret) { instance_double(StackMaster::ParameterResolvers::Secret) }
42
+ before do
43
+ allow(StackMaster::ParameterResolvers::Secret).to receive(:new).and_return(secret)
44
+ end
45
+ it "does not prompt for the secret key" do
46
+ expect(secret).not_to receive(:resolve)
47
+ validator.perform
48
+ end
49
+ end
37
50
  end
38
51
 
39
52
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stack_master
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Hodgkiss
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-11-23 00:00:00.000000000 Z
12
+ date: 2016-11-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -362,6 +362,7 @@ files:
362
362
  - lib/stack_master/template_compilers/json.rb
363
363
  - lib/stack_master/template_compilers/sparkle_formation.rb
364
364
  - lib/stack_master/template_compilers/yaml.rb
365
+ - lib/stack_master/template_utils.rb
365
366
  - lib/stack_master/test_driver/cloud_formation.rb
366
367
  - lib/stack_master/test_driver/s3.rb
367
368
  - lib/stack_master/testing.rb
@@ -373,6 +374,7 @@ files:
373
374
  - script/buildkite/clean.sh
374
375
  - script/buildkite_rspec.sh
375
376
  - spec/fixtures/parameters/myapp_vpc.yml
377
+ - spec/fixtures/parameters/myapp_vpc_with_secrets.yml
376
378
  - spec/fixtures/stack_master.yml
377
379
  - spec/fixtures/templates/json/valid_myapp_vpc.json
378
380
  - spec/fixtures/templates/myapp_vpc.json
@@ -417,6 +419,7 @@ files:
417
419
  - spec/stack_master/template_compilers/json_spec.rb
418
420
  - spec/stack_master/template_compilers/sparkle_formation_spec.rb
419
421
  - spec/stack_master/template_compilers/yaml_spec.rb
422
+ - spec/stack_master/template_utils_spec.rb
420
423
  - spec/stack_master/test_driver/cloud_formation_spec.rb
421
424
  - spec/stack_master/test_driver/s3_spec.rb
422
425
  - spec/stack_master/utils_spec.rb
@@ -468,6 +471,7 @@ test_files:
468
471
  - features/support/env.rb
469
472
  - features/validate.feature
470
473
  - spec/fixtures/parameters/myapp_vpc.yml
474
+ - spec/fixtures/parameters/myapp_vpc_with_secrets.yml
471
475
  - spec/fixtures/stack_master.yml
472
476
  - spec/fixtures/templates/json/valid_myapp_vpc.json
473
477
  - spec/fixtures/templates/myapp_vpc.json
@@ -512,6 +516,7 @@ test_files:
512
516
  - spec/stack_master/template_compilers/json_spec.rb
513
517
  - spec/stack_master/template_compilers/sparkle_formation_spec.rb
514
518
  - spec/stack_master/template_compilers/yaml_spec.rb
519
+ - spec/stack_master/template_utils_spec.rb
515
520
  - spec/stack_master/test_driver/cloud_formation_spec.rb
516
521
  - spec/stack_master/test_driver/s3_spec.rb
517
522
  - spec/stack_master/utils_spec.rb