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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -0
  3. data/features/apply.feature +1 -1
  4. data/features/apply_with_s3.feature +106 -0
  5. data/features/step_definitions/stack_steps.rb +5 -0
  6. data/features/support/env.rb +1 -0
  7. data/lib/stack_master.rb +78 -58
  8. data/lib/stack_master/aws_driver/s3.rb +66 -0
  9. data/lib/stack_master/cli.rb +1 -0
  10. data/lib/stack_master/commands/apply.rb +52 -5
  11. data/lib/stack_master/commands/init.rb +2 -0
  12. data/lib/stack_master/commands/list_stacks.rb +2 -0
  13. data/lib/stack_master/commands/outputs.rb +2 -0
  14. data/lib/stack_master/commands/status.rb +3 -0
  15. data/lib/stack_master/parameter_resolver.rb +1 -1
  16. data/lib/stack_master/parameter_resolvers/secret.rb +2 -0
  17. data/lib/stack_master/stack.rb +20 -13
  18. data/lib/stack_master/stack_definition.rb +63 -13
  19. data/lib/stack_master/stack_differ.rb +2 -0
  20. data/lib/stack_master/stack_events/fetcher.rb +1 -1
  21. data/lib/stack_master/stack_events/presenter.rb +1 -1
  22. data/lib/stack_master/stack_events/streamer.rb +1 -1
  23. data/lib/stack_master/template_compiler.rb +3 -1
  24. data/lib/stack_master/template_compilers/cfndsl.rb +4 -2
  25. data/lib/stack_master/template_compilers/json.rb +4 -0
  26. data/lib/stack_master/template_compilers/sparkle_formation.rb +5 -0
  27. data/lib/stack_master/template_compilers/yaml.rb +4 -0
  28. data/lib/stack_master/test_driver/cloud_formation.rb +50 -36
  29. data/lib/stack_master/test_driver/s3.rb +34 -0
  30. data/lib/stack_master/testing.rb +1 -0
  31. data/lib/stack_master/utils.rb +19 -0
  32. data/lib/stack_master/version.rb +1 -1
  33. data/spec/fixtures/stack_master.yml +4 -1
  34. data/spec/stack_master/aws_driver/s3_spec.rb +130 -0
  35. data/spec/stack_master/commands/apply_spec.rb +26 -0
  36. data/spec/stack_master/config_spec.rb +8 -1
  37. data/spec/stack_master/parameter_resolver_spec.rb +5 -0
  38. data/spec/stack_master/sparkle_formation/user_data_file_spec.rb +2 -0
  39. data/spec/stack_master/stack_events/presenter_spec.rb +1 -1
  40. data/spec/stack_master/stack_spec.rb +23 -5
  41. data/spec/stack_master/template_compiler_spec.rb +1 -0
  42. data/spec/stack_master/template_compilers/cfndsl_spec.rb +2 -0
  43. data/spec/stack_master/test_driver/s3_spec.rb +17 -0
  44. data/stack_master.gemspec +0 -1
  45. metadata +10 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 462256c45f5be50e9afe763ac0bd7dc8a466ce98
4
- data.tar.gz: d2feec3d48f34397eef2e26223c15e9745fd5bcb
3
+ metadata.gz: 24f9543391ced08e41349c5cd75aaecacce6aab2
4
+ data.tar.gz: 0130dc01c3bfacea757155caf6896aef4daaebaf
5
5
  SHA512:
6
- metadata.gz: c78d5094529357d8e17581d46092a7b8f5ff155cf8ffb2081be549fb081c331bf96d97f35e6cb6f6de208fd6edb79baba2f2766b459667a87acf05de0c08525b
7
- data.tar.gz: ddc6dae60758049e6b01a538254e29e14c048d5c82fc63ef3afa59c897f1e7575531c124db1e2fc702aae803ead82a7e3b28d85aabd14f1ca7af0e94cbfa1f41
6
+ metadata.gz: 95bf919587f2d04956c97ef82caa0f9d79747b2272e1c97075549950a5d5606dbf084cfba5ef65a4e61935a4d3c11fd13c06183f02e9305f55e8f98353ded7be
7
+ data.tar.gz: d5523800109d4f3ac1a5a04a4f2f3246ad51d2014b76234c2b35c54f18e39b24a8b7fe4e5b9696682d1b299f8bf5b969961b0d49355c54381d2cc247e7cde26d
data/README.md CHANGED
@@ -95,6 +95,28 @@ stacks:
95
95
  purpose: vpc
96
96
  ```
97
97
 
98
+ ## S3
99
+
100
+ StackMaster can optionally use S3 to store the templates before creating a stack.
101
+ This requires to configure an S3 bucket in stack_master.yml:
102
+
103
+ ```yaml
104
+ stack_defaults:
105
+ s3:
106
+ bucket: my_bucket_name
107
+ prefix: cfn_templates/my-awesome-app
108
+ region: us-west-2
109
+ ```
110
+
111
+ Additional files can be configured to be uploaded to S3 alongside the templates:
112
+ ```yaml
113
+ stacks:
114
+ production:
115
+ myapp-vpc:
116
+ template: myapp_vpc.rb
117
+ files:
118
+ - userdata.sh
119
+ ```
98
120
  ## Directories
99
121
 
100
122
  - `templates` - CloudFormation, SparkleFormation or CfnDsl templates.
@@ -90,7 +90,7 @@ Feature: Apply command
90
90
  | Parameters diff: |
91
91
  | KeyName: my-key |
92
92
  | aborted |
93
- And the output should not match /2020-10-29 00:00:00 \+[0-9]{4} myapp-vpc AWS::CloudFormation::Stack CREATE_COMPLETE/
93
+ And the output should not match /2020-10-29 00:00:00 \+[0-9]{4} myapp-vpc AWS::CloudFormation::Stack CREATE_COMPLETE/
94
94
  Then the exit status should be 0
95
95
 
96
96
  Scenario: Run apply with region only and create 2 stacks
@@ -0,0 +1,106 @@
1
+ Feature: Apply command
2
+
3
+ Background:
4
+ Given a file named "stack_master.yml" with:
5
+ """
6
+ stack_defaults:
7
+ s3:
8
+ bucket: my-bucket
9
+ region: us-east-1
10
+ prefix: cfn_templates/my-app
11
+ stacks:
12
+ us_east_1:
13
+ myapp_vpc:
14
+ template: myapp_vpc.rb
15
+ files:
16
+ - user_data.sh
17
+ """
18
+ And a directory named "parameters"
19
+ And a file named "parameters/myapp_vpc.yml" with:
20
+ """
21
+ KeyName: my-key
22
+ """
23
+ And a file named "parameters/myapp_web.yml" with:
24
+ """
25
+ VpcId: vpc-blah
26
+ """
27
+ And a directory named "templates"
28
+ And a file named "files/user_data.sh" with:
29
+ """
30
+ #!/bin/bash
31
+ echo "HI"
32
+ """
33
+ And a file named "templates/myapp_vpc.rb" with:
34
+ """
35
+ SparkleFormation.new(:myapp_vpc) do
36
+ description "Test template"
37
+ set!('AWSTemplateFormatVersion', '2010-09-09')
38
+
39
+ parameters.key_name do
40
+ description 'Key name'
41
+ type 'String'
42
+ end
43
+
44
+ resources.vpc do
45
+ type 'AWS::EC2::VPC'
46
+ properties do
47
+ cidr_block '10.200.0.0/16'
48
+ end
49
+ end
50
+
51
+ outputs do
52
+ vpc_id do
53
+ description 'A VPC ID'
54
+ value ref!(:vpc)
55
+ end
56
+ end
57
+ end
58
+ """
59
+
60
+ Scenario: Run apply and create a new stack
61
+ Given I stub the following stack events:
62
+ | stack_id | event_id | stack_name | logical_resource_id | resource_status | resource_type | timestamp |
63
+ | 1 | 1 | myapp-vpc | TestSg | CREATE_COMPLETE | AWS::EC2::SecurityGroup | 2020-10-29 00:00:00 |
64
+ | 1 | 1 | myapp-vpc | myapp-vpc | CREATE_COMPLETE | AWS::CloudFormation::Stack | 2020-10-29 00:00:00 |
65
+ When I run `stack_master apply us-east-1 myapp-vpc --trace`
66
+ And the output should contain all of these lines:
67
+ | Stack diff: |
68
+ | + "Vpc": { |
69
+ | Parameters diff: |
70
+ | KeyName: my-key |
71
+ And the output should match /2020-10-29 00:00:00 \+[0-9]{4} myapp-vpc AWS::CloudFormation::Stack CREATE_COMPLETE/
72
+ And an S3 file in bucket "my-bucket" with key "cfn_templates/my-app/myapp_vpc.json" exists with content:
73
+ """
74
+ {
75
+ "Description": "Test template",
76
+ "AWSTemplateFormatVersion": "2010-09-09",
77
+ "Parameters": {
78
+ "KeyName": {
79
+ "Description": "Key name",
80
+ "Type": "String"
81
+ }
82
+ },
83
+ "Resources": {
84
+ "Vpc": {
85
+ "Type": "AWS::EC2::VPC",
86
+ "Properties": {
87
+ "CidrBlock": "10.200.0.0/16"
88
+ }
89
+ }
90
+ },
91
+ "Outputs": {
92
+ "VpcId": {
93
+ "Description": "A VPC ID",
94
+ "Value": {
95
+ "Ref": "Vpc"
96
+ }
97
+ }
98
+ }
99
+ }
100
+ """
101
+ And an S3 file in bucket "my-bucket" with key "cfn_templates/my-app/user_data.sh" exists with content:
102
+ """
103
+ #!/bin/bash
104
+ echo "HI"
105
+ """
106
+ Then the exit status should be 0
@@ -64,3 +64,8 @@ end
64
64
  Given(/^I stub CloudFormation validate calls to fail validation with message "([^"]*)"$/) do |message|
65
65
  allow(StackMaster.cloud_formation_driver).to receive(:validate_template).and_raise(Aws::CloudFormation::Errors::ValidationError.new('', message))
66
66
  end
67
+
68
+ When(/^an S3 file in bucket "([^"]*)" with key "([^"]*)" exists with content:$/) do |bucket, key, body|
69
+ file = StackMaster.s3_driver.find_file(bucket: bucket, object_key: key)
70
+ expect(file).to eq body
71
+ end
@@ -12,4 +12,5 @@ end
12
12
 
13
13
  Before do
14
14
  StackMaster.cloud_formation_driver.reset
15
+ StackMaster.s3_driver.reset
15
16
  end
data/lib/stack_master.rb CHANGED
@@ -1,69 +1,82 @@
1
1
  require "commander"
2
2
  require "yaml"
3
- require "virtus"
4
3
  require "aws-sdk"
5
- require "diffy"
6
4
  require "colorize"
7
- require "table_print"
8
5
  require 'active_support/core_ext/string'
9
- require "erb"
10
- require 'sparkle_formation'
11
- require 'dotgpg'
12
- require 'ruby-progressbar'
13
-
14
- require "stack_master/ctrl_c"
15
- require "stack_master/sparkle_formation/user_data_file"
16
- require "stack_master/command"
17
- require "stack_master/version"
18
- require "stack_master/stack"
19
- require "stack_master/prompter"
20
- require "stack_master/aws_driver/cloud_formation"
21
- require "stack_master/test_driver/cloud_formation"
22
- require "stack_master/stack_events/fetcher"
23
- require "stack_master/stack_events/presenter"
24
- require "stack_master/stack_events/streamer"
25
- require "stack_master/stack_states"
26
- require "stack_master/stack_status"
27
- require "stack_master/sns_topic_finder"
28
- require "stack_master/security_group_finder"
29
- require "stack_master/parameter_loader"
30
- require "stack_master/parameter_resolver"
31
- require "stack_master/resolver_array"
32
- require "stack_master/parameter_resolvers/ami_finder"
33
- require "stack_master/parameter_resolvers/stack_output"
34
- require "stack_master/parameter_resolvers/secret"
35
- require "stack_master/parameter_resolvers/sns_topic_name"
36
- require "stack_master/parameter_resolvers/security_group"
37
- require "stack_master/parameter_resolvers/latest_ami_by_tags"
38
- require "stack_master/parameter_resolvers/latest_ami"
39
- require "stack_master/utils"
40
- require "stack_master/config"
41
- require "stack_master/paged_response_accumulator"
42
- require "stack_master/stack_definition"
43
- require "stack_master/template_compiler"
44
- require "stack_master/template_compilers/sparkle_formation"
45
- require "stack_master/template_compilers/json"
46
- require "stack_master/template_compilers/yaml"
47
- require "stack_master/template_compilers/cfndsl"
48
- require "stack_master/commands/terminal_helper"
49
- require "stack_master/commands/apply"
50
- require "stack_master/change_set"
51
- require "stack_master/commands/events"
52
- require "stack_master/commands/outputs"
53
- require "stack_master/commands/init"
54
- require "stack_master/commands/diff"
55
- require "stack_master/commands/list_stacks"
56
- require "stack_master/commands/validate"
57
- require "stack_master/commands/resources"
58
- require "stack_master/commands/delete"
59
- require "stack_master/commands/status"
60
- require "stack_master/stack_differ"
61
- require "stack_master/validator"
62
- require "stack_master/cli"
63
6
 
64
7
  module StackMaster
65
8
  extend self
66
9
 
10
+ autoload :Initializable, 'stack_master/utils/initializable'
11
+ autoload :ChangeSet, 'stack_master/change_set'
12
+ autoload :CLI, 'stack_master/cli'
13
+ autoload :CtrlC, 'stack_master/ctrl_c'
14
+ autoload :Command, 'stack_master/command'
15
+ autoload :Version, 'stack_master/version'
16
+ autoload :Stack, 'stack_master/stack'
17
+ autoload :Prompter, 'stack_master/prompter'
18
+ autoload :StackStates, 'stack_master/stack_states'
19
+ autoload :StackStatus, 'stack_master/stack_status'
20
+ autoload :SnsTopicFinder, 'stack_master/sns_topic_finder'
21
+ autoload :SecurityGroupFinder, 'stack_master/security_group_finder'
22
+ autoload :ParameterLoader, 'stack_master/parameter_loader'
23
+ autoload :ParameterResolver, 'stack_master/parameter_resolver'
24
+ autoload :ResolverArray, 'stack_master/resolver_array'
25
+ autoload :Resolver, 'stack_master/resolver_array'
26
+ autoload :Utils, 'stack_master/utils'
27
+ autoload :Config, 'stack_master/config'
28
+ autoload :PagedResponseAccumulator, 'stack_master/paged_response_accumulator'
29
+ autoload :StackDefinition, 'stack_master/stack_definition'
30
+ autoload :TemplateCompiler, 'stack_master/template_compiler'
31
+
32
+ autoload :StackDiffer, 'stack_master/stack_differ'
33
+ autoload :Validator, 'stack_master/validator'
34
+
35
+ require 'stack_master/template_compilers/sparkle_formation'
36
+ require 'stack_master/template_compilers/json'
37
+ require 'stack_master/template_compilers/yaml'
38
+ require 'stack_master/template_compilers/cfndsl'
39
+
40
+ module Commands
41
+ autoload :TerminalHelper, 'stack_master/commands/terminal_helper'
42
+ autoload :Apply, 'stack_master/commands/apply'
43
+ autoload :Events, 'stack_master/commands/events'
44
+ autoload :Outputs, 'stack_master/commands/outputs'
45
+ autoload :Init, 'stack_master/commands/init'
46
+ autoload :Diff, 'stack_master/commands/diff'
47
+ autoload :ListStacks, 'stack_master/commands/list_stacks'
48
+ autoload :Validate, 'stack_master/commands/validate'
49
+ autoload :Resources, 'stack_master/commands/resources'
50
+ autoload :Delete, 'stack_master/commands/delete'
51
+ autoload :Status, 'stack_master/commands/status'
52
+ end
53
+
54
+ module ParameterResolvers
55
+ autoload :AmiFinder, 'stack_master/parameter_resolvers/ami_finder'
56
+ autoload :StackOutput, 'stack_master/parameter_resolvers/stack_output'
57
+ autoload :Secret, 'stack_master/parameter_resolvers/secret'
58
+ autoload :SnsTopicName, 'stack_master/parameter_resolvers/sns_topic_name'
59
+ autoload :SecurityGroup, 'stack_master/parameter_resolvers/security_group'
60
+ autoload :LatestAmiByTags, 'stack_master/parameter_resolvers/latest_ami_by_tags'
61
+ autoload :LatestAmi, 'stack_master/parameter_resolvers/latest_ami'
62
+ end
63
+
64
+ module AwsDriver
65
+ autoload :CloudFormation, 'stack_master/aws_driver/cloud_formation'
66
+ autoload :S3, 'stack_master/aws_driver/s3'
67
+ end
68
+
69
+ module TestDriver
70
+ autoload :CloudFormation, 'stack_master/test_driver/cloud_formation'
71
+ autoload :S3, 'stack_master/test_driver/s3'
72
+ end
73
+
74
+ module StackEvents
75
+ autoload :Fetcher, 'stack_master/stack_events/fetcher'
76
+ autoload :Presenter, 'stack_master/stack_events/presenter'
77
+ autoload :Streamer, 'stack_master/stack_events/streamer'
78
+ end
79
+
67
80
  def interactive?
68
81
  !non_interactive?
69
82
  end
@@ -106,6 +119,14 @@ module StackMaster
106
119
  @cloud_formation_driver = value
107
120
  end
108
121
 
122
+ def s3_driver
123
+ @s3_driver ||= AwsDriver::S3.new
124
+ end
125
+
126
+ def s3_driver=(value)
127
+ @s3_driver = value
128
+ end
129
+
109
130
  def stdout
110
131
  @stdout || $stdout
111
132
  end
@@ -126,4 +147,3 @@ module StackMaster
126
147
  @stderr = io
127
148
  end
128
149
  end
129
-
@@ -0,0 +1,66 @@
1
+ require 'digest/md5'
2
+
3
+ module StackMaster
4
+ module AwsDriver
5
+ class S3ConfigurationError < StandardError; end
6
+
7
+ class S3
8
+ def set_region(region)
9
+ @region = region
10
+ @s3 = nil
11
+ end
12
+
13
+ def upload_files(bucket: nil, prefix: nil, region: nil, files: {})
14
+ raise StackMaster::AwsDriver::S3ConfigurationError, 'A bucket must be specified in order to use S3' unless bucket
15
+
16
+ return if files.empty?
17
+
18
+ s3 = new_s3_client(region: region)
19
+
20
+ current_objects = s3.list_objects(
21
+ prefix: prefix,
22
+ bucket: bucket
23
+ ).map(&:contents).flatten.inject({}){|h,obj|
24
+ h.merge(obj.key => obj)
25
+ }
26
+
27
+ StackMaster.stdout.puts "Uploading files to S3:"
28
+
29
+ files.each do |template, file|
30
+ body = file.fetch(:body)
31
+ path = file.fetch(:path)
32
+ object_key = template.dup
33
+ object_key.prepend("#{prefix}/") if prefix
34
+ compiled_template_md5 = Digest::MD5.hexdigest(body).to_s
35
+ s3_md5 = current_objects[object_key] ? current_objects[object_key].etag.gsub("\"", '') : nil
36
+
37
+ next if compiled_template_md5 == s3_md5
38
+ s3_uri = "s3://#{bucket}/#{object_key}"
39
+ StackMaster.stdout.print "- #{File.basename(path)} => #{s3_uri} "
40
+
41
+ s3.put_object(
42
+ bucket: bucket,
43
+ key: object_key,
44
+ body: body,
45
+ metadata: { md5: compiled_template_md5 }
46
+ )
47
+ StackMaster.stdout.puts "done."
48
+ end
49
+ end
50
+
51
+ def url(bucket:, prefix:, region:, template:)
52
+ if region == 'us-east-1'
53
+ ["https://s3.amazonaws.com", bucket, prefix, template].compact.join('/')
54
+ else
55
+ ["https://s3-#{region}.amazonaws.com", bucket, prefix, template].compact.join('/')
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def new_s3_client(region: nil)
62
+ Aws::S3::Client.new(region: region || @region)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,4 +1,5 @@
1
1
  require 'commander'
2
+ require 'table_print'
2
3
 
3
4
  module StackMaster
4
5
  class CLI
@@ -4,10 +4,11 @@ module StackMaster
4
4
  include Command
5
5
  include Commander::UI
6
6
  include StackMaster::Prompter
7
- TEMPLATE_TOO_LARGE_ERROR_MESSAGE = 'The (space compressed) stack is larger than the limit set by AWS. See http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html'
7
+ TEMPLATE_TOO_LARGE_ERROR_MESSAGE = 'The (space compressed) stack is larger than the limit set by AWS. See http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html'.freeze
8
8
 
9
9
  def initialize(config, stack_definition, options = {})
10
10
  @config = config
11
+ @s3_config = stack_definition.s3
11
12
  @stack_definition = stack_definition
12
13
  @from_time = Time.now
13
14
  end
@@ -26,6 +27,10 @@ module StackMaster
26
27
  @cf ||= StackMaster.cloud_formation_driver
27
28
  end
28
29
 
30
+ def s3
31
+ @s3 ||= StackMaster.s3_driver
32
+ end
33
+
29
34
  def stack
30
35
  @stack ||= Stack.find(region, stack_name)
31
36
  end
@@ -38,6 +43,10 @@ module StackMaster
38
43
  !stack.nil?
39
44
  end
40
45
 
46
+ def use_s3?
47
+ !@s3_config.empty?
48
+ end
49
+
41
50
  def diff_stacks
42
51
  StackDiffer.new(proposed_stack, stack).output_diff
43
52
  end
@@ -51,9 +60,10 @@ module StackMaster
51
60
  end
52
61
 
53
62
  def create_stack
54
- unless ask?("Create stack (y/n)? ")
63
+ unless ask?('Create stack (y/n)? ')
55
64
  failed!("Stack creation aborted")
56
65
  end
66
+ upload_files
57
67
  cf.create_stack(stack_options.merge(tags: proposed_stack.aws_tags))
58
68
  end
59
69
 
@@ -73,17 +83,54 @@ module StackMaster
73
83
  ChangeSet.delete(@change_set.id)
74
84
  halt! "Stack update aborted"
75
85
  end
86
+ upload_files
76
87
  execute_change_set
77
88
  end
78
89
 
90
+ def upload_files
91
+ return unless use_s3?
92
+ s3.upload_files(s3_options)
93
+ end
94
+
95
+ def template_method
96
+ use_s3? ? :template_url : :template_body
97
+ end
98
+
99
+ def template_value
100
+ if use_s3?
101
+ s3.url(bucket: @s3_config['bucket'], prefix: @s3_config['prefix'], region: @s3_config['region'], template: @stack_definition.s3_template_file_name)
102
+ else
103
+ proposed_stack.maybe_compressed_template_body
104
+ end
105
+ end
106
+
107
+ def files_to_upload
108
+ return {} unless use_s3?
109
+ @stack_definition.s3_files.tap do |files|
110
+ files[@stack_definition.s3_template_file_name] = {
111
+ path: @stack_definition.template_file_path,
112
+ body: proposed_stack.maybe_compressed_template_body
113
+ }
114
+ end
115
+ end
116
+
79
117
  def stack_options
80
118
  {
81
119
  stack_name: stack_name,
82
- template_body: proposed_stack.maybe_compressed_template_body,
83
120
  parameters: proposed_stack.aws_parameters,
84
121
  capabilities: ['CAPABILITY_IAM'],
85
122
  notification_arns: proposed_stack.notification_arns,
86
- stack_policy_body: proposed_stack.stack_policy_body
123
+ stack_policy_body: proposed_stack.stack_policy_body,
124
+ template_method => template_value
125
+ }
126
+ end
127
+
128
+ def s3_options
129
+ {
130
+ bucket: @s3_config['bucket'],
131
+ prefix: @s3_config['prefix'],
132
+ region: @s3_config['region'],
133
+ files: files_to_upload
87
134
  }
88
135
  end
89
136
 
@@ -110,7 +157,7 @@ module StackMaster
110
157
  end
111
158
 
112
159
  def ensure_valid_template_body_size!
113
- if proposed_stack.too_big?
160
+ if proposed_stack.too_big?(use_s3?)
114
161
  failed! TEMPLATE_TOO_LARGE_ERROR_MESSAGE
115
162
  end
116
163
  end