stack_master 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/lib/stack_master/commands/terminal_helper.rb +14 -1
- data/lib/stack_master/parameter_resolvers/secret.rb +7 -2
- data/lib/stack_master/version.rb +1 -1
- metadata +21 -216
- data/.gitignore +0 -18
- data/.rspec +0 -2
- data/.travis.yml +0 -12
- data/CODE_OF_CONDUCT.md +0 -73
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -27
- data/apply_demo.gif +0 -0
- data/example/simple/Gemfile +0 -3
- data/example/simple/parameters/myapp_vpc.yml +0 -1
- data/example/simple/parameters/myapp_web.yml +0 -2
- data/example/simple/stack_master.yml +0 -13
- data/example/simple/templates/myapp_vpc.rb +0 -39
- data/example/simple/templates/myapp_web.rb +0 -16
- data/features/apply.feature +0 -392
- data/features/apply_with_compile_time_parameters.feature +0 -93
- data/features/apply_with_env_parameters.feature +0 -49
- data/features/apply_with_parameter_store_parameters.feature +0 -47
- data/features/apply_with_s3.feature +0 -106
- data/features/delete.feature +0 -29
- data/features/diff.feature +0 -179
- data/features/events.feature +0 -33
- data/features/init.feature +0 -6
- data/features/outputs.feature +0 -45
- data/features/region_aliases.feature +0 -62
- data/features/resources.feature +0 -42
- data/features/stack_defaults.feature +0 -82
- data/features/status.feature +0 -118
- data/features/step_definitions/parameter_store_steps.rb +0 -14
- data/features/step_definitions/stack_steps.rb +0 -71
- data/features/support/env.rb +0 -16
- data/features/validate.feature +0 -46
- data/logo.png +0 -0
- data/script/buildkite/bundle.sh +0 -5
- data/script/buildkite/clean.sh +0 -3
- data/script/buildkite_rspec.sh +0 -27
- data/spec/fixtures/parameters/myapp_vpc.yml +0 -1
- data/spec/fixtures/parameters/myapp_vpc_with_secrets.yml +0 -3
- data/spec/fixtures/sparkle_pack_integration/my_sparkle_pack/lib/my_sparkle_pack.rb +0 -1
- data/spec/fixtures/sparkle_pack_integration/my_sparkle_pack/lib/sparkleformation/dynamics/my_dynamic.rb +0 -5
- data/spec/fixtures/sparkle_pack_integration/templates/dynamics/local_dynamic.rb +0 -5
- data/spec/fixtures/sparkle_pack_integration/templates/template_with_dynamic.rb +0 -3
- data/spec/fixtures/sparkle_pack_integration/templates/template_with_dynamic_from_pack.rb +0 -3
- data/spec/fixtures/stack_master.yml +0 -49
- data/spec/fixtures/templates/json/valid_myapp_vpc.json +0 -53
- data/spec/fixtures/templates/myapp_vpc.json +0 -1
- data/spec/fixtures/templates/rb/cfndsl/sample.json +0 -28
- data/spec/fixtures/templates/rb/cfndsl/sample.rb +0 -16
- data/spec/fixtures/templates/yml/valid_myapp_vpc.yml +0 -35
- data/spec/fixtures/test/.gitkeep +0 -0
- data/spec/spec_helper.rb +0 -102
- data/spec/stack_master/aws_driver/s3_spec.rb +0 -130
- data/spec/stack_master/change_set_spec.rb +0 -70
- data/spec/stack_master/command_spec.rb +0 -66
- data/spec/stack_master/commands/apply_spec.rb +0 -259
- data/spec/stack_master/commands/delete_spec.rb +0 -40
- data/spec/stack_master/commands/init_spec.rb +0 -17
- data/spec/stack_master/commands/status_spec.rb +0 -44
- data/spec/stack_master/commands/validate_spec.rb +0 -27
- data/spec/stack_master/config_spec.rb +0 -153
- data/spec/stack_master/paged_response_accumulator_spec.rb +0 -39
- data/spec/stack_master/parameter_loader_spec.rb +0 -110
- data/spec/stack_master/parameter_resolver_spec.rb +0 -148
- data/spec/stack_master/parameter_resolvers/ami_finder_spec.rb +0 -68
- data/spec/stack_master/parameter_resolvers/env_spec.rb +0 -35
- data/spec/stack_master/parameter_resolvers/latest_ami_by_tags_spec.rb +0 -33
- data/spec/stack_master/parameter_resolvers/latest_ami_spec.rb +0 -46
- data/spec/stack_master/parameter_resolvers/parameter_store_spec.rb +0 -50
- data/spec/stack_master/parameter_resolvers/secret_spec.rb +0 -66
- data/spec/stack_master/parameter_resolvers/security_group_spec.rb +0 -19
- data/spec/stack_master/parameter_resolvers/security_groups_spec.rb +0 -32
- data/spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb +0 -43
- data/spec/stack_master/parameter_resolvers/stack_output_spec.rb +0 -127
- data/spec/stack_master/prompter_spec.rb +0 -23
- data/spec/stack_master/resolver_array_spec.rb +0 -42
- data/spec/stack_master/security_group_finder_spec.rb +0 -49
- data/spec/stack_master/sns_topic_finder_spec.rb +0 -25
- data/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb +0 -47
- data/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb +0 -47
- data/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb +0 -36
- data/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb +0 -47
- data/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb +0 -37
- data/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb +0 -27
- data/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb +0 -36
- data/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb +0 -28
- data/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb +0 -41
- data/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb +0 -65
- data/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb +0 -28
- data/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb +0 -35
- data/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb +0 -52
- data/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb +0 -40
- data/spec/stack_master/sparkle_formation/template_file_spec.rb +0 -147
- data/spec/stack_master/stack_definition_spec.rb +0 -70
- data/spec/stack_master/stack_differ_spec.rb +0 -46
- data/spec/stack_master/stack_events/fetcher_spec.rb +0 -40
- data/spec/stack_master/stack_events/presenter_spec.rb +0 -18
- data/spec/stack_master/stack_events/streamer_spec.rb +0 -47
- data/spec/stack_master/stack_spec.rb +0 -184
- data/spec/stack_master/template_compiler_spec.rb +0 -39
- data/spec/stack_master/template_compilers/cfndsl_spec.rb +0 -22
- data/spec/stack_master/template_compilers/json_spec.rb +0 -32
- data/spec/stack_master/template_compilers/sparkle_formation_spec.rb +0 -116
- data/spec/stack_master/template_compilers/yaml_spec.rb +0 -20
- data/spec/stack_master/template_utils_spec.rb +0 -21
- data/spec/stack_master/test_driver/cloud_formation_spec.rb +0 -64
- data/spec/stack_master/test_driver/s3_spec.rb +0 -17
- data/spec/stack_master/utils_spec.rb +0 -30
- data/spec/stack_master/validator_spec.rb +0 -56
- data/spec/stack_master_spec.rb +0 -81
- data/spec/support/gemfiles/Gemfile.activesupport-4.0.0 +0 -5
- data/spec/support/validator_spec.rb +0 -23
- data/stack_master.gemspec +0 -46
- data/stacktemplates/parameter_region.yml +0 -3
- data/stacktemplates/parameter_stack_name.yml +0 -3
- data/stacktemplates/stack.json.erb +0 -20
- data/stacktemplates/stack_master.yml.erb +0 -6
@@ -1,70 +0,0 @@
|
|
1
|
-
RSpec.describe StackMaster::ChangeSet do
|
2
|
-
let(:cf) { instance_double(Aws::CloudFormation::Client) }
|
3
|
-
let(:region) { 'us-east-1' }
|
4
|
-
let(:stack_name) { 'myapp-vpc' }
|
5
|
-
let(:change_set_name) { 'changeset-123' }
|
6
|
-
|
7
|
-
describe '.generate_change_set_name' do
|
8
|
-
context 'valid name' do
|
9
|
-
it 'creates a valid name' do
|
10
|
-
expect(StackMaster::ChangeSet.generate_change_set_name('foobar')).to match(/^foobar-StackMaster[-a-zA-Z0-9]*$/)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe '.create' do
|
16
|
-
before do
|
17
|
-
allow(StackMaster::ChangeSet).to receive(:generate_change_set_name).and_return(change_set_name)
|
18
|
-
allow(StackMaster).to receive(:cloud_formation_driver).and_return(cf)
|
19
|
-
allow(cf).to receive(:create_change_set).and_return(double(id: 'id-1'))
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'successful response' do
|
23
|
-
before do
|
24
|
-
allow(cf).to receive(:describe_change_set).with(change_set_name: 'id-1', next_token: nil).and_return(double(next_token: nil, changes: [], :changes= => nil, :next_token= => nil, status: 'CREATE_COMPLETE'))
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'calls the create change set API with the addition of a name' do
|
28
|
-
change_set = StackMaster::ChangeSet.create(stack_name: '123')
|
29
|
-
expect(cf).to have_received(:create_change_set).with(
|
30
|
-
stack_name: '123',
|
31
|
-
change_set_name: change_set_name
|
32
|
-
)
|
33
|
-
expect(change_set.failed?).to eq false
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'unsuccessful response' do
|
38
|
-
before do
|
39
|
-
allow(cf).to receive(:describe_change_set).with(change_set_name: 'id-1', next_token: nil).and_return(double(next_token: nil, changes: [], :changes= => nil, :next_token= => nil, status: 'FAILED', status_reason: 'No changes'))
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'is marked as failed' do
|
43
|
-
change_set = StackMaster::ChangeSet.create(stack_name: '123')
|
44
|
-
expect(change_set.failed?).to eq true
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
describe '#display' do
|
50
|
-
context 'a successful response' do
|
51
|
-
let(:target) { OpenStruct.new(name: 'GroupDescription', attribute: 'Properties', requires_recreation: 'Always') }
|
52
|
-
let(:changes) { [
|
53
|
-
OpenStruct.new(resource_change: OpenStruct.new(replacement: 'True', action: 'Modify', resource_type: 'EC2::Instance', logical_resource_id: '123', details: [OpenStruct.new(target: target, change_source: 'DirectModification', evaluation: 'Static', causing_entity: 'blah')]))
|
54
|
-
] }
|
55
|
-
let(:cf_response) { double(next_token: nil, changes: changes, :changes= => nil, :next_token= => nil, status: 'FAILED', status_reason: 'No changes') }
|
56
|
-
let(:io) { StringIO.new }
|
57
|
-
subject(:change_set) { StackMaster::ChangeSet.new(cf_response) }
|
58
|
-
let(:message) { io.string }
|
59
|
-
before { change_set.display(io) }
|
60
|
-
|
61
|
-
it 'outputs key data' do
|
62
|
-
expect(message).to include 'Replace EC2::Instance 123'
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'outputs detail data' do
|
66
|
-
expect(message).to include 'Properties.GroupDescription. Always requires recreation. Triggered by: DirectModification.blah'
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
RSpec.describe StackMaster::Command do
|
2
|
-
let(:command_class) {
|
3
|
-
Class.new do
|
4
|
-
include StackMaster::Command
|
5
|
-
|
6
|
-
def initialize(callable = nil, halt = nil)
|
7
|
-
@callable = callable
|
8
|
-
@halt = halt
|
9
|
-
end
|
10
|
-
|
11
|
-
attr_reader :finished
|
12
|
-
|
13
|
-
def perform
|
14
|
-
instance_eval(&@callable) if @callable
|
15
|
-
halt! if @halt
|
16
|
-
@finished = true
|
17
|
-
false
|
18
|
-
end
|
19
|
-
end
|
20
|
-
}
|
21
|
-
|
22
|
-
context 'when failed is not called' do
|
23
|
-
it 'is successful' do
|
24
|
-
expect(command_class.perform.success?).to eq true
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'when failed is called' do
|
29
|
-
it 'is not successful' do
|
30
|
-
expect(command_class.perform(proc { failed }).success?).to eq false
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe '#halt!' do
|
35
|
-
it 'exits the command' do
|
36
|
-
expect(command_class.perform(nil, true).finished).to_not eq true
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'when a CF error occurs' do
|
41
|
-
it 'outputs the message' do
|
42
|
-
error_proc = proc {
|
43
|
-
raise Aws::CloudFormation::Errors::ServiceError.new('a', 'the message')
|
44
|
-
}
|
45
|
-
expect { command_class.perform(error_proc) }.to output(/the message/).to_stderr
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context 'when a template compilation error occurs' do
|
50
|
-
it 'outputs the message' do
|
51
|
-
error_proc = proc {
|
52
|
-
raise StackMaster::TemplateCompiler::TemplateCompilationFailed.new('the message')
|
53
|
-
}
|
54
|
-
expect { command_class.perform(error_proc) }.to output(/the message/).to_stderr
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'outputs the exception\'s cause' do
|
58
|
-
exception_with_cause = StackMaster::TemplateCompiler::TemplateCompilationFailed.new('the message')
|
59
|
-
allow(exception_with_cause).to receive(:cause).and_return(RuntimeError.new('the cause message'))
|
60
|
-
error_proc = proc {
|
61
|
-
raise exception_with_cause
|
62
|
-
}
|
63
|
-
expect { command_class.perform(error_proc) }.to output(/Caused by: RuntimeError the cause message/).to_stderr
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,259 +0,0 @@
|
|
1
|
-
RSpec.describe StackMaster::Commands::Apply do
|
2
|
-
let(:cf) { instance_double(Aws::CloudFormation::Client) }
|
3
|
-
let(:s3) { instance_double(Aws::S3::Client) }
|
4
|
-
let(:region) { 'us-east-1' }
|
5
|
-
let(:stack_name) { 'myapp-vpc' }
|
6
|
-
let(:config) { double(find_stack: stack_definition) }
|
7
|
-
let(:role_arn) { 'test_service_role_arn' }
|
8
|
-
let(:notification_arn) { 'test_arn' }
|
9
|
-
let(:stack_definition) { StackMaster::StackDefinition.new(base_dir: '/base_dir', region: region, stack_name: stack_name) }
|
10
|
-
let(:template_body) { '{}' }
|
11
|
-
let(:template_format) { :json }
|
12
|
-
let(:parameters) { { 'param_1' => 'hello' } }
|
13
|
-
let(:proposed_stack) { StackMaster::Stack.new(template_body: template_body, template_format: template_format, tags: { 'environment' => 'production' } , parameters: parameters, role_arn: role_arn, notification_arns: [notification_arn], stack_policy_body: stack_policy_body ) }
|
14
|
-
let(:stack_policy_body) { '{}' }
|
15
|
-
let(:change_set) { double(display: true, failed?: false, id: '1') }
|
16
|
-
|
17
|
-
before do
|
18
|
-
allow(StackMaster::Stack).to receive(:find).with(region, stack_name).and_return(stack)
|
19
|
-
allow(StackMaster::Stack).to receive(:generate).with(stack_definition, config).and_return(proposed_stack)
|
20
|
-
allow(config).to receive(:stack_defaults).and_return({})
|
21
|
-
allow(Aws::CloudFormation::Client).to receive(:new).and_return(cf)
|
22
|
-
allow(Aws::S3::Client).to receive(:new).and_return(s3)
|
23
|
-
allow(cf).to receive(:create_stack)
|
24
|
-
allow(StackMaster::StackDiffer).to receive(:new).with(proposed_stack, stack).and_return double.as_null_object
|
25
|
-
allow(StackMaster::StackEvents::Streamer).to receive(:stream)
|
26
|
-
allow(StackMaster).to receive(:interactive?).and_return(false)
|
27
|
-
allow(cf).to receive(:create_change_set).and_return(OpenStruct.new(id: '1'))
|
28
|
-
allow(StackMaster::ChangeSet).to receive(:create).and_return(change_set)
|
29
|
-
allow(cf).to receive(:execute_change_set).and_return(OpenStruct.new(id: '1'))
|
30
|
-
allow(cf).to receive(:set_stack_policy)
|
31
|
-
end
|
32
|
-
|
33
|
-
def apply
|
34
|
-
StackMaster::Commands::Apply.perform(config, stack_definition)
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'the stack exist' do
|
38
|
-
let(:stack) { StackMaster::Stack.new(stack_id: '1') }
|
39
|
-
|
40
|
-
it 'creates a change set' do
|
41
|
-
apply
|
42
|
-
expect(StackMaster::ChangeSet).to have_received(:create).with(
|
43
|
-
stack_name: stack_name,
|
44
|
-
template_body: proposed_stack.template_body,
|
45
|
-
parameters: [
|
46
|
-
{ parameter_key: 'param_1', parameter_value: 'hello' }
|
47
|
-
],
|
48
|
-
tags: [
|
49
|
-
{ key: 'environment', value: 'production' }
|
50
|
-
],
|
51
|
-
capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
|
52
|
-
role_arn: role_arn,
|
53
|
-
notification_arns: [notification_arn]
|
54
|
-
)
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'streams events' do
|
58
|
-
Timecop.freeze(Time.local(1990)) do
|
59
|
-
apply
|
60
|
-
expect(StackMaster::StackEvents::Streamer).to have_received(:stream).with(stack_name, region, io: STDOUT, from: Time.now)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'attaches a stack policy to the stack' do
|
65
|
-
apply
|
66
|
-
expect(cf).to have_received(:set_stack_policy).with(
|
67
|
-
stack_name: stack_name,
|
68
|
-
stack_policy_body: stack_policy_body
|
69
|
-
)
|
70
|
-
end
|
71
|
-
|
72
|
-
context 'stack policy is not changed' do
|
73
|
-
let(:stack) { StackMaster::Stack.new(stack_id: '1', stack_policy_body: stack_policy_body) }
|
74
|
-
|
75
|
-
it 'does not set a stack policy' do
|
76
|
-
apply
|
77
|
-
expect(cf).to_not have_received(:set_stack_policy)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
context 'when using s3' do
|
82
|
-
before do
|
83
|
-
stack_definition.s3 = {
|
84
|
-
'bucket' => 'my-bucket',
|
85
|
-
'prefix' => 'my-prefix',
|
86
|
-
'region' => 'us-east-1',
|
87
|
-
}
|
88
|
-
stack_definition.template = 'my-template.rb'
|
89
|
-
allow(s3).to receive(:list_objects).and_return([])
|
90
|
-
allow(s3).to receive(:put_object)
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'uploads to the correct URL' do
|
94
|
-
apply
|
95
|
-
expect(s3).to have_received(:put_object).with(
|
96
|
-
bucket: 'my-bucket',
|
97
|
-
key: 'my-prefix/my-template.json',
|
98
|
-
body: template_body,
|
99
|
-
metadata: { md5: Digest::MD5.hexdigest(template_body).to_s }
|
100
|
-
)
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'uploads to S3 before creating a changeset' do
|
104
|
-
expect(s3).to receive(:put_object).ordered
|
105
|
-
expect(StackMaster::ChangeSet).to receive(:create).ordered
|
106
|
-
apply
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
context 'the changeset failed to create' do
|
111
|
-
before do
|
112
|
-
allow(StackMaster::ChangeSet).to receive(:delete)
|
113
|
-
allow(change_set).to receive(:failed?).and_return(true)
|
114
|
-
allow(change_set).to receive(:status_reason).and_return('reason')
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'outputs the status reason' do
|
118
|
-
expect { apply }.to output(/reason/).to_stdout
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
context 'user decides to not apply the change set' do
|
123
|
-
before do
|
124
|
-
allow(StackMaster).to receive(:non_interactive_answer).and_return('n')
|
125
|
-
allow(StackMaster::ChangeSet).to receive(:delete)
|
126
|
-
allow(StackMaster::ChangeSet).to receive(:execute)
|
127
|
-
apply
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'deletes the change set' do
|
131
|
-
expect(StackMaster::ChangeSet).to have_received(:delete).with(change_set.id)
|
132
|
-
end
|
133
|
-
|
134
|
-
it "doesn't execute the change set" do
|
135
|
-
expect(StackMaster::ChangeSet).to_not have_received(:execute).with(change_set.id)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
context 'the stack does not exist' do
|
141
|
-
let(:stack) { nil }
|
142
|
-
|
143
|
-
it 'creates a change set for a new stack' do
|
144
|
-
apply
|
145
|
-
expect(StackMaster::ChangeSet).to have_received(:create).with(
|
146
|
-
stack_name: stack_name,
|
147
|
-
template_body: proposed_stack.template_body,
|
148
|
-
parameters: [
|
149
|
-
{ parameter_key: 'param_1', parameter_value: 'hello' }
|
150
|
-
],
|
151
|
-
tags: [
|
152
|
-
{ key: 'environment', value: 'production' }
|
153
|
-
],
|
154
|
-
capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
|
155
|
-
role_arn: role_arn,
|
156
|
-
notification_arns: [notification_arn],
|
157
|
-
change_set_type: 'CREATE'
|
158
|
-
)
|
159
|
-
end
|
160
|
-
|
161
|
-
context 'on_failure option is set' do
|
162
|
-
it 'calls the create stack API method' do
|
163
|
-
options = Commander::Command::Options.new
|
164
|
-
options.on_failure = 'ROLLBACK'
|
165
|
-
StackMaster::Commands::Apply.perform(config, stack_definition, options)
|
166
|
-
apply
|
167
|
-
expect(cf).to have_received(:create_stack).with(
|
168
|
-
stack_name: stack_name,
|
169
|
-
template_body: proposed_stack.template_body,
|
170
|
-
parameters: [
|
171
|
-
{ parameter_key: 'param_1', parameter_value: 'hello' }
|
172
|
-
],
|
173
|
-
tags: [
|
174
|
-
{ key: 'environment', value: 'production' }
|
175
|
-
],
|
176
|
-
capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
|
177
|
-
role_arn: role_arn,
|
178
|
-
notification_arns: [notification_arn],
|
179
|
-
on_failure: 'ROLLBACK'
|
180
|
-
)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'attaches a stack policy to the created stack' do
|
185
|
-
apply
|
186
|
-
expect(cf).to have_received(:set_stack_policy).with(
|
187
|
-
stack_name: stack_name,
|
188
|
-
stack_policy_body: stack_policy_body
|
189
|
-
)
|
190
|
-
end
|
191
|
-
|
192
|
-
context 'the stack is too large' do
|
193
|
-
let(:big_string) { 'x' * 60000 }
|
194
|
-
let(:template_body) do
|
195
|
-
"{\"a\":\"#{big_string}\"}"
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'exits with a message' do
|
199
|
-
expect { apply }.to output(/The \(space compressed\) stack is larger than the limit set by AWS/).to_stderr
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
it 'streams events' do
|
204
|
-
Timecop.freeze(Time.local(1990)) do
|
205
|
-
apply
|
206
|
-
expect(StackMaster::StackEvents::Streamer).to have_received(:stream).with(stack_name, region, io: STDOUT, from: Time.now)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
context 'user decides to not create a stack' do
|
211
|
-
before do
|
212
|
-
allow(StackMaster).to receive(:non_interactive_answer).and_return('n')
|
213
|
-
allow(cf).to receive(:delete_stack)
|
214
|
-
allow(StackMaster::ChangeSet).to receive(:execute)
|
215
|
-
apply
|
216
|
-
end
|
217
|
-
|
218
|
-
it 'deletes the stack' do
|
219
|
-
expect(cf).to have_received(:delete_stack).with(stack_name: stack_name)
|
220
|
-
end
|
221
|
-
|
222
|
-
it "doesn't execute the change set" do
|
223
|
-
expect(StackMaster::ChangeSet).to_not have_received(:execute).with(change_set.id)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
context 'user uses ctrl+c' do
|
228
|
-
before do
|
229
|
-
allow(StackMaster).to receive(:non_interactive_answer).and_return('n')
|
230
|
-
allow(cf).to receive(:delete_stack)
|
231
|
-
allow(StackMaster::ChangeSet).to receive(:create).and_raise(StackMaster::CtrlC)
|
232
|
-
end
|
233
|
-
|
234
|
-
it "deletes the stack" do
|
235
|
-
expect(cf).to receive(:delete_stack).with(stack_name: stack_name)
|
236
|
-
expect { apply }.to raise_error
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
context 'one or more parameters are empty' do
|
242
|
-
let(:stack) { StackMaster::Stack.new(stack_id: '1', parameters: parameters) }
|
243
|
-
let(:parameters) { { 'param_1' => nil } }
|
244
|
-
|
245
|
-
it "doesn't allow apply" do
|
246
|
-
expect { apply }.to_not output(/Continue and apply the stack/).to_stdout
|
247
|
-
end
|
248
|
-
|
249
|
-
it 'outputs a description of the problem' do
|
250
|
-
expect { apply }.to output(/Empty\/blank parameters detected/).to_stderr
|
251
|
-
end
|
252
|
-
|
253
|
-
it 'outputs where param files are loaded from' do
|
254
|
-
stack_definition.parameter_files.each do |parameter_file|
|
255
|
-
expect { apply }.to output(/#{parameter_file}/).to_stderr
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
RSpec.describe StackMaster::Commands::Delete do
|
2
|
-
|
3
|
-
subject(:delete) { described_class.new(stack_name, region) }
|
4
|
-
let(:cf) { Aws::CloudFormation::Client.new }
|
5
|
-
let(:region) { 'us-east-1' }
|
6
|
-
let(:stack_name) { 'mystack' }
|
7
|
-
|
8
|
-
before do
|
9
|
-
StackMaster.cloud_formation_driver.set_region(region)
|
10
|
-
allow(Aws::CloudFormation::Client).to receive(:new).with(region: region, retry_limit: 10).and_return(cf)
|
11
|
-
allow(delete).to receive(:ask?).and_return('y')
|
12
|
-
allow(StackMaster::StackEvents::Streamer).to receive(:stream)
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "#perform" do
|
16
|
-
context "The stack exists" do
|
17
|
-
before do
|
18
|
-
cf.stub_responses(:describe_stacks, stacks: [{ stack_id: "ABC", stack_name: stack_name, creation_time: Time.now, stack_status: 'UPDATE_COMPLETE', parameters: []}])
|
19
|
-
|
20
|
-
end
|
21
|
-
it "deletes the stack and tails the events" do
|
22
|
-
expect(cf).to receive(:delete_stack).with({:stack_name => region})
|
23
|
-
expect(StackMaster::StackEvents::Streamer).to receive(:stream)
|
24
|
-
delete.perform
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context "The stack does not exist" do
|
29
|
-
before do
|
30
|
-
cf.stub_responses(:describe_stacks, Aws::CloudFormation::Errors::ValidationError.new("x", "y"))
|
31
|
-
end
|
32
|
-
it "raises an error" do
|
33
|
-
expect(StackMaster::StackEvents::Streamer).to_not receive(:stream)
|
34
|
-
expect(cf).to_not receive(:delete_stack)
|
35
|
-
delete.perform
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
RSpec.describe StackMaster::Commands::Init do
|
2
|
-
|
3
|
-
subject(:init_command) { described_class.new(false, region, stack_name) }
|
4
|
-
let(:region) { "us-east-1" }
|
5
|
-
let(:stack_name) { "test-stack" }
|
6
|
-
|
7
|
-
describe "#perform" do
|
8
|
-
it "creates all the expected files" do
|
9
|
-
expect(IO).to receive(:write).with("stack_master.yml", "stacks:\n us-east-1:\n test-stack:\n template: test-stack.json\n tags:\n environment: production\n")
|
10
|
-
expect(IO).to receive(:write).with("parameters/test_stack.yml", "# Add parameters here:\n# param1: value1\n# param2: value2\n")
|
11
|
-
expect(IO).to receive(:write).with("parameters/us-east-1/test_stack.yml", "# Add parameters here:\n# param1: value1\n# param2: value2\n")
|
12
|
-
expect(IO).to receive(:write).with("templates/test-stack.json", "{\n \"AWSTemplateFormatVersion\" : \"2010-09-09\",\n \"Description\" : \"Cloudformation stack for test-stack\",\n\n \"Parameters\" : {\n \"InstanceType\" : {\n \"Description\" : \"EC2 instance type\",\n \"Type\" : \"String\"\n }\n },\n\n \"Mappings\" : {\n },\n\n \"Resources\" : {\n },\n\n \"Outputs\" : {\n }\n}\n")
|
13
|
-
init_command.perform()
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|