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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/lib/stack_master/commands/terminal_helper.rb +14 -1
  4. data/lib/stack_master/parameter_resolvers/secret.rb +7 -2
  5. data/lib/stack_master/version.rb +1 -1
  6. metadata +21 -216
  7. data/.gitignore +0 -18
  8. data/.rspec +0 -2
  9. data/.travis.yml +0 -12
  10. data/CODE_OF_CONDUCT.md +0 -73
  11. data/Gemfile +0 -4
  12. data/LICENSE.txt +0 -22
  13. data/Rakefile +0 -27
  14. data/apply_demo.gif +0 -0
  15. data/example/simple/Gemfile +0 -3
  16. data/example/simple/parameters/myapp_vpc.yml +0 -1
  17. data/example/simple/parameters/myapp_web.yml +0 -2
  18. data/example/simple/stack_master.yml +0 -13
  19. data/example/simple/templates/myapp_vpc.rb +0 -39
  20. data/example/simple/templates/myapp_web.rb +0 -16
  21. data/features/apply.feature +0 -392
  22. data/features/apply_with_compile_time_parameters.feature +0 -93
  23. data/features/apply_with_env_parameters.feature +0 -49
  24. data/features/apply_with_parameter_store_parameters.feature +0 -47
  25. data/features/apply_with_s3.feature +0 -106
  26. data/features/delete.feature +0 -29
  27. data/features/diff.feature +0 -179
  28. data/features/events.feature +0 -33
  29. data/features/init.feature +0 -6
  30. data/features/outputs.feature +0 -45
  31. data/features/region_aliases.feature +0 -62
  32. data/features/resources.feature +0 -42
  33. data/features/stack_defaults.feature +0 -82
  34. data/features/status.feature +0 -118
  35. data/features/step_definitions/parameter_store_steps.rb +0 -14
  36. data/features/step_definitions/stack_steps.rb +0 -71
  37. data/features/support/env.rb +0 -16
  38. data/features/validate.feature +0 -46
  39. data/logo.png +0 -0
  40. data/script/buildkite/bundle.sh +0 -5
  41. data/script/buildkite/clean.sh +0 -3
  42. data/script/buildkite_rspec.sh +0 -27
  43. data/spec/fixtures/parameters/myapp_vpc.yml +0 -1
  44. data/spec/fixtures/parameters/myapp_vpc_with_secrets.yml +0 -3
  45. data/spec/fixtures/sparkle_pack_integration/my_sparkle_pack/lib/my_sparkle_pack.rb +0 -1
  46. data/spec/fixtures/sparkle_pack_integration/my_sparkle_pack/lib/sparkleformation/dynamics/my_dynamic.rb +0 -5
  47. data/spec/fixtures/sparkle_pack_integration/templates/dynamics/local_dynamic.rb +0 -5
  48. data/spec/fixtures/sparkle_pack_integration/templates/template_with_dynamic.rb +0 -3
  49. data/spec/fixtures/sparkle_pack_integration/templates/template_with_dynamic_from_pack.rb +0 -3
  50. data/spec/fixtures/stack_master.yml +0 -49
  51. data/spec/fixtures/templates/json/valid_myapp_vpc.json +0 -53
  52. data/spec/fixtures/templates/myapp_vpc.json +0 -1
  53. data/spec/fixtures/templates/rb/cfndsl/sample.json +0 -28
  54. data/spec/fixtures/templates/rb/cfndsl/sample.rb +0 -16
  55. data/spec/fixtures/templates/yml/valid_myapp_vpc.yml +0 -35
  56. data/spec/fixtures/test/.gitkeep +0 -0
  57. data/spec/spec_helper.rb +0 -102
  58. data/spec/stack_master/aws_driver/s3_spec.rb +0 -130
  59. data/spec/stack_master/change_set_spec.rb +0 -70
  60. data/spec/stack_master/command_spec.rb +0 -66
  61. data/spec/stack_master/commands/apply_spec.rb +0 -259
  62. data/spec/stack_master/commands/delete_spec.rb +0 -40
  63. data/spec/stack_master/commands/init_spec.rb +0 -17
  64. data/spec/stack_master/commands/status_spec.rb +0 -44
  65. data/spec/stack_master/commands/validate_spec.rb +0 -27
  66. data/spec/stack_master/config_spec.rb +0 -153
  67. data/spec/stack_master/paged_response_accumulator_spec.rb +0 -39
  68. data/spec/stack_master/parameter_loader_spec.rb +0 -110
  69. data/spec/stack_master/parameter_resolver_spec.rb +0 -148
  70. data/spec/stack_master/parameter_resolvers/ami_finder_spec.rb +0 -68
  71. data/spec/stack_master/parameter_resolvers/env_spec.rb +0 -35
  72. data/spec/stack_master/parameter_resolvers/latest_ami_by_tags_spec.rb +0 -33
  73. data/spec/stack_master/parameter_resolvers/latest_ami_spec.rb +0 -46
  74. data/spec/stack_master/parameter_resolvers/parameter_store_spec.rb +0 -50
  75. data/spec/stack_master/parameter_resolvers/secret_spec.rb +0 -66
  76. data/spec/stack_master/parameter_resolvers/security_group_spec.rb +0 -19
  77. data/spec/stack_master/parameter_resolvers/security_groups_spec.rb +0 -32
  78. data/spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb +0 -43
  79. data/spec/stack_master/parameter_resolvers/stack_output_spec.rb +0 -127
  80. data/spec/stack_master/prompter_spec.rb +0 -23
  81. data/spec/stack_master/resolver_array_spec.rb +0 -42
  82. data/spec/stack_master/security_group_finder_spec.rb +0 -49
  83. data/spec/stack_master/sns_topic_finder_spec.rb +0 -25
  84. data/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb +0 -47
  85. data/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb +0 -47
  86. data/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb +0 -36
  87. data/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb +0 -47
  88. data/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb +0 -37
  89. data/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb +0 -27
  90. data/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb +0 -36
  91. data/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb +0 -28
  92. data/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb +0 -41
  93. data/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb +0 -65
  94. data/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb +0 -28
  95. data/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb +0 -35
  96. data/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb +0 -52
  97. data/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb +0 -40
  98. data/spec/stack_master/sparkle_formation/template_file_spec.rb +0 -147
  99. data/spec/stack_master/stack_definition_spec.rb +0 -70
  100. data/spec/stack_master/stack_differ_spec.rb +0 -46
  101. data/spec/stack_master/stack_events/fetcher_spec.rb +0 -40
  102. data/spec/stack_master/stack_events/presenter_spec.rb +0 -18
  103. data/spec/stack_master/stack_events/streamer_spec.rb +0 -47
  104. data/spec/stack_master/stack_spec.rb +0 -184
  105. data/spec/stack_master/template_compiler_spec.rb +0 -39
  106. data/spec/stack_master/template_compilers/cfndsl_spec.rb +0 -22
  107. data/spec/stack_master/template_compilers/json_spec.rb +0 -32
  108. data/spec/stack_master/template_compilers/sparkle_formation_spec.rb +0 -116
  109. data/spec/stack_master/template_compilers/yaml_spec.rb +0 -20
  110. data/spec/stack_master/template_utils_spec.rb +0 -21
  111. data/spec/stack_master/test_driver/cloud_formation_spec.rb +0 -64
  112. data/spec/stack_master/test_driver/s3_spec.rb +0 -17
  113. data/spec/stack_master/utils_spec.rb +0 -30
  114. data/spec/stack_master/validator_spec.rb +0 -56
  115. data/spec/stack_master_spec.rb +0 -81
  116. data/spec/support/gemfiles/Gemfile.activesupport-4.0.0 +0 -5
  117. data/spec/support/validator_spec.rb +0 -23
  118. data/stack_master.gemspec +0 -46
  119. data/stacktemplates/parameter_region.yml +0 -3
  120. data/stacktemplates/parameter_stack_name.yml +0 -3
  121. data/stacktemplates/stack.json.erb +0 -20
  122. data/stacktemplates/stack_master.yml.erb +0 -6
@@ -1,68 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::AmiFinder do
2
- subject(:resolver) { described_class.new('us-east-1') }
3
- let(:ec2) { Aws::EC2::Client.new }
4
-
5
- before do
6
- allow(Aws::EC2::Client).to receive(:new).and_return(ec2)
7
- end
8
-
9
- describe '#build_filters_from_string' do
10
- context 'when a single key-value pair is specified' do
11
- it 'returns an array with a single hash' do
12
- expect(resolver.build_filters_from_string('my-attr=my-value', nil)).to eq [
13
- { name: 'my-attr', values: ['my-value']}
14
- ]
15
- end
16
- end
17
-
18
- context 'when multiple key-value pairs are specified' do
19
- it 'returns an array with multiple hashes' do
20
- expect(resolver.build_filters_from_string('my-attr=my-value,foo=bar', nil)).to eq [
21
- { name: 'my-attr', values: ['my-value']},
22
- { name: 'foo', values: ['bar']}
23
- ]
24
- end
25
- end
26
-
27
- context 'when a prefix is supplied' do
28
- it 'adds the prefix to the filter' do
29
- expect(resolver.build_filters_from_string('my-tag=my-value', 'tag')).to eq [
30
- { name: 'tag:my-tag', values: ['my-value']}
31
- ]
32
- end
33
- end
34
- end
35
-
36
- describe '#build_filters_from_hash' do
37
- it 'outputs a hash of values in the format expected by the AWS API' do
38
- expect(resolver.build_filters_from_hash({'foo' => 'bacon'})).to eq([{name: 'foo', values: ['bacon']}])
39
- end
40
- end
41
-
42
- describe '#find_latest_ami' do
43
- let(:filter) { [{ name: "String", values: ["String"]}] }
44
-
45
- context 'when matches are found' do
46
- before do
47
- ec2.stub_responses(:describe_images, images: [
48
- { image_id: '1', creation_date: '2015-01-02 00:00:00', tags: [{ key: 'my-tag', value: 'my-value' }] },
49
- { image_id: '2', creation_date: '2015-01-03 00:00:00', tags: [{ key: 'my-tag', value: 'my-value' }] }
50
- ])
51
- end
52
-
53
- it 'returns the latest one' do
54
- expect(resolver.find_latest_ami(filter).image_id).to eq '2'
55
- end
56
- end
57
-
58
- context 'when no matches are found' do
59
- before do
60
- ec2.stub_responses(:describe_images, images: [])
61
- end
62
-
63
- it 'returns nil' do
64
- expect(resolver.find_latest_ami(filter)).to be_nil
65
- end
66
- end
67
- end
68
- end
@@ -1,35 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::Env do
2
-
3
- describe '#resolve' do
4
-
5
- subject(:resolver) { described_class.new(nil, double(region: 'us-east-1')) }
6
- let(:environment_variable_name) { 'TEST' }
7
- let(:error) { "The environment variable #{environment_variable_name} is not set" }
8
-
9
- before(:each) do
10
- ENV.delete(environment_variable_name)
11
- end
12
-
13
- context 'the environment variable is defined' do
14
- it 'should return the environment variable value' do
15
- ENV[environment_variable_name] = 'a'
16
- expect(resolver.resolve(environment_variable_name)).to eq 'a'
17
- end
18
- end
19
-
20
- context 'the environment variable is undefined' do
21
- it 'should raise and error' do
22
- expect { resolver.resolve(environment_variable_name) }
23
- .to raise_error(ArgumentError, error)
24
- end
25
- end
26
-
27
- context 'the environment variable is defined but empty' do
28
- it 'should return the empty string' do
29
- ENV[environment_variable_name] = ''
30
- expect(resolver.resolve(environment_variable_name)).to eq ''
31
- end
32
- end
33
-
34
- end
35
- end
@@ -1,33 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::LatestAmiByTags do
2
- let(:config) { double(base_dir: '/base') }
3
- let(:stack_definition) { double(stack_name: 'mystack', region: 'us-east-1') }
4
- subject(:resolver) { described_class.new(config, stack_definition) }
5
- let(:ec2) { Aws::EC2::Client.new }
6
-
7
- before do
8
- allow(Aws::EC2::Client).to receive(:new).and_return(ec2)
9
- end
10
-
11
- context 'when matches are found' do
12
- before do
13
- ec2.stub_responses(:describe_images, images: [
14
- { image_id: '1', creation_date: '2015-01-02 00:00:00', tags: [{ key: 'my-tag', value: 'my-value' }] },
15
- { image_id: '2', creation_date: '2015-01-03 00:00:00', tags: [{ key: 'my-tag', value: 'my-value' }] }
16
- ])
17
- end
18
-
19
- it 'returns the latest one' do
20
- expect(resolver.resolve('my-tag=my-value')).to eq '2'
21
- end
22
- end
23
-
24
- context 'when no matches are found' do
25
- before do
26
- ec2.stub_responses(:describe_images, images: [])
27
- end
28
-
29
- it 'returns nil' do
30
- expect(resolver.resolve('my-tag=my-value')).to be_nil
31
- end
32
- end
33
- end
@@ -1,46 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::LatestAmi do
2
- let(:config) { double(base_dir: '/base') }
3
- let(:stack_definition) { double(stack_name: 'mystack', region: 'us-east-1') }
4
- subject(:resolver) { described_class.new(config, stack_definition) }
5
- let(:ec2) { Aws::EC2::Client.new }
6
-
7
- before do
8
- allow(Aws::EC2::Client).to receive(:new).and_return(ec2)
9
- end
10
-
11
- context 'when matches are found' do
12
- before do
13
- ec2.stub_responses(:describe_images, images: [
14
- { image_id: '1', creation_date: '2015-01-02 00:00:00', name: 'foo' },
15
- { image_id: '2', creation_date: '2015-01-03 00:00:00', name: 'foo' }
16
- ])
17
- end
18
-
19
- it 'returns the latest one' do
20
- expect(resolver.resolve('filters' => {'name' => 'foo'})).to eq '2'
21
- end
22
- end
23
-
24
- context 'when no matches are found' do
25
- before do
26
- ec2.stub_responses(:describe_images, images: [])
27
- end
28
-
29
- it 'returns nil' do
30
- expect(resolver.resolve('filters' => {'name' => 'foo'})).to be_nil
31
- end
32
- end
33
-
34
- context 'when an owner_id is passed' do
35
- let(:ami_finder) { StackMaster::ParameterResolvers::AmiFinder.new('us-east-1') }
36
- before do
37
- expect(StackMaster::ParameterResolvers::AmiFinder).to receive(:new).and_return(ami_finder)
38
- allow(ami_finder).to receive(:build_filters_from_hash).and_call_original
39
- end
40
-
41
- it 'calls find_latest_ami with the owner and filters' do
42
- expect(ami_finder).to receive(:find_latest_ami).with([{name: 'foo', values: ['bacon']}], ['123456'])
43
- resolver.resolve({'owners' => 123456, 'filters' => {'foo' => 'bacon'} })
44
- end
45
- end
46
- end
@@ -1,50 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::ParameterStore do
2
-
3
- describe '#resolve' do
4
-
5
- let(:config) { double(base_dir: '/base') }
6
- let(:stack_definition) { double(stack_name: 'mystack', region: 'us-east-1') }
7
- subject(:resolver) { described_class.new(config, stack_definition) }
8
- let(:parameter_name) { 'TEST' }
9
- let(:parameter_value) { 'TEST' }
10
- let(:unknown_parameter_name) { 'NOTEST' }
11
- let(:unencryptable_parameter_name) { 'SECRETTEST' }
12
-
13
-
14
- context 'the parameter is defined' do
15
- before do
16
- Aws.config[:ssm] = {
17
- stub_responses: {
18
- get_parameter: {
19
- parameter: {
20
- name: parameter_name,
21
- value: parameter_value,
22
- type: "SecureString",
23
- version: 1
24
- }
25
- }
26
- }
27
- }
28
- end
29
-
30
- it 'should return the parameter value' do
31
- expect(resolver.resolve(parameter_name)).to eq parameter_value
32
- end
33
- end
34
-
35
- context 'the parameter is undefined' do
36
- before do
37
- Aws.config[:ssm] = {
38
- stub_responses: {
39
- get_parameter:
40
- Aws::SSM::Errors::ParameterNotFound.new(unknown_parameter_name, "Parameter #{unknown_parameter_name} not found")
41
- }
42
- }
43
- end
44
- it 'should raise and error' do
45
- expect { resolver.resolve(unknown_parameter_name) }
46
- .to raise_error(StackMaster::ParameterResolvers::ParameterStore::ParameterNotFound, "Unable to find #{unknown_parameter_name} in Parameter Store")
47
- end
48
- end
49
- end
50
- end
@@ -1,66 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::Secret do
2
- let(:base_dir) { '/base_dir' }
3
- let(:config) { double(base_dir: base_dir) }
4
- let(:stack_definition) { double(secret_file: secrets_file_name, stack_name: 'mystack', region: 'us-east-1') }
5
- subject(:resolve_secret) { StackMaster::ParameterResolvers::Secret.new(config, stack_definition).resolve(value) }
6
- let(:value) { 'my_file/my_secret_key' }
7
- let(:secrets_file_name) { "my_file.yml.gpg" }
8
- let(:file_path) { "#{base_dir}/secrets/#{secrets_file_name}" }
9
-
10
- context 'the secret file does not exist' do
11
- before do
12
- allow(File).to receive(:exist?).with(file_path).and_return(false)
13
- end
14
-
15
- it 'raises an ArgumentError with the location of the expected secret file' do
16
- expect {
17
- resolve_secret
18
- }.to raise_error(ArgumentError, /#{file_path}/)
19
- end
20
- end
21
-
22
- context 'no secret file is specified for the stack definition' do
23
- before do
24
- allow(stack_definition).to receive(:secret_file).and_return(nil)
25
- end
26
-
27
- it 'raises an ArgumentError with the location of the expected secret file' do
28
- expect {
29
- resolve_secret
30
- }.to raise_error(ArgumentError, /No secret_file defined/)
31
- end
32
- end
33
-
34
- context 'the secret file exists' do
35
- let(:dir) { double(Dotgpg::Dir) }
36
- let(:decrypted_file) { <<EOF }
37
- secret_key_1: secret_value_1
38
- secret_key_2: secret_value_2
39
- EOF
40
-
41
- before do
42
- allow(File).to receive(:exist?).with(file_path).and_return(true)
43
- allow(Dotgpg::Dir).to receive(:closest).with(file_path).and_return(dir)
44
- allow(dir).to receive(:decrypt).with("secrets/#{secrets_file_name}", anything)
45
- allow(StringIO).to receive(:new).and_return(double(string: decrypted_file))
46
- end
47
-
48
- context 'the secret key does not exist' do
49
- let(:value) { 'unknown_secret' }
50
-
51
- it 'raises a secret not found error' do
52
- expect {
53
- resolve_secret
54
- }.to raise_error(StackMaster::ParameterResolvers::Secret::SecretNotFound)
55
- end
56
- end
57
-
58
- context 'the secret key exists' do
59
- let(:value) { 'secret_key_2' }
60
-
61
- it 'returns the secret' do
62
- expect(resolve_secret).to eq('secret_value_2')
63
- end
64
- end
65
- end
66
- end
@@ -1,19 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::SecurityGroup do
2
- describe "#resolve" do
3
- subject(:resolver) { described_class.new(nil, double(region: 'us-east-1')) }
4
- let(:finder) { instance_double(StackMaster::SecurityGroupFinder) }
5
- let(:sg_id) { 'sg-id' }
6
- let(:sg_name) { 'sg-name' }
7
-
8
- before do
9
- allow(StackMaster::SecurityGroupFinder).to receive(:new).with('us-east-1').and_return finder
10
- expect(finder).to receive(:find).once.with(sg_name).and_return sg_id
11
- end
12
-
13
- context 'when given a single SG name' do
14
- it "resolves the security group" do
15
- expect(resolver.resolve(sg_name)).to eq sg_id
16
- end
17
- end
18
- end
19
- end
@@ -1,32 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::SecurityGroups do
2
- describe "#resolve" do
3
- subject(:resolver) { described_class.new(nil, double(region: 'us-east-1')) }
4
- let(:finder) { instance_double(StackMaster::SecurityGroupFinder) }
5
- let(:sg_id) { 'sg-id' }
6
- let(:sg_name) { 'sg-name' }
7
-
8
- before do
9
- allow(StackMaster::SecurityGroupFinder).to receive(:new).with('us-east-1').and_return finder
10
- expect(finder).to receive(:find).once.with(sg_name).and_return sg_id
11
- end
12
-
13
- context 'when given a single SG name' do
14
- it "resolves the security group" do
15
- expect(resolver.resolve(sg_name)).to eq sg_id
16
- end
17
- end
18
-
19
- context 'when given a an array of SG names' do
20
- let(:sg_id2) { 'sg-id2' }
21
- let(:sg_name2) { 'sg-name2' }
22
-
23
- before do
24
- expect(finder).to receive(:find).once.with(sg_name2).and_return sg_id2
25
- end
26
-
27
- it "resolves the security groups" do
28
- expect(resolver.resolve([sg_name, sg_name2])).to eq "#{sg_id},#{sg_id2}"
29
- end
30
- end
31
- end
32
- end
@@ -1,43 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::SnsTopicName do
2
- let(:region) { 'us-east-1' }
3
- let(:stack_name) { 'my-stack' }
4
- let(:config) { double }
5
-
6
- def resolve(value)
7
- described_class.new(config, double(region: 'us-east-1')).resolve(value)
8
- end
9
-
10
- subject(:resolved_value) { resolve(value) }
11
-
12
- context 'when given a hash' do
13
- let(:value) { { not_expected: 1} }
14
-
15
- it 'raises an error' do
16
- expect {
17
- resolved_value
18
- }.to raise_error(ArgumentError)
19
- end
20
- end
21
-
22
- context 'when given a string value' do
23
- let(:value) { 'my-topic-name' }
24
-
25
- context 'the stack and sns topic name exist' do
26
- before do
27
- allow_any_instance_of(StackMaster::SnsTopicFinder).to receive(:find).with(value).and_return('myresolvedvalue')
28
- end
29
-
30
- it 'resolves the value' do
31
- expect(resolved_value).to eq 'myresolvedvalue'
32
- end
33
- end
34
-
35
- context "the topic doesn't exist" do
36
- it 'raises topic not found' do
37
- expect {
38
- resolved_value
39
- }.to raise_error(StackMaster::ParameterResolvers::SnsTopicName::TopicNotFound)
40
- end
41
- end
42
- end
43
- end
@@ -1,127 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolvers::StackOutput do
2
- let(:region) { 'us-east-1' }
3
- let(:stack_name) { 'my-stack' }
4
- let(:resolver) { described_class.new(config, double(region: 'us-east-1')) }
5
- let(:cf) { Aws::CloudFormation::Client.new }
6
- let(:config) { double(:unalias_region => region) }
7
-
8
- def resolve(value)
9
- resolver.resolve(value)
10
- end
11
-
12
- subject(:resolved_value) { resolve(value) }
13
-
14
- context 'when given an invalid string value' do
15
- let(:value) { 'stack-name-without-output' }
16
-
17
- it 'raises an error' do
18
- expect {
19
- resolved_value
20
- }.to raise_error(ArgumentError)
21
- end
22
- end
23
-
24
- context 'when given a hash' do
25
- let(:value) { { not_expected: 1} }
26
-
27
- it 'raises an error' do
28
- expect {
29
- resolved_value
30
- }.to raise_error(ArgumentError)
31
- end
32
- end
33
-
34
- context 'when given a valid string value' do
35
- let(:value) { 'my-stack/MyOutput' }
36
- let(:stacks) { [{ stack_name: 'blah', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs}] }
37
- let(:outputs) { [] }
38
-
39
- before do
40
- allow(Aws::CloudFormation::Client).to receive(:new).and_return(cf)
41
- cf.stub_responses(:describe_stacks, stacks: stacks)
42
- end
43
-
44
- context 'the stack and output exist' do
45
- let(:outputs) { [{output_key: 'MyOutput', output_value: 'myresolvedvalue'}] }
46
-
47
- it 'resolves the value' do
48
- expect(resolved_value).to eq 'myresolvedvalue'
49
- end
50
-
51
- it 'caches stacks for the lifetime of the instance' do
52
- resolver.resolve(value)
53
- resolver.resolve(value)
54
- end
55
- end
56
-
57
- context "the stack doesn't exist" do
58
- let(:stacks) { nil }
59
-
60
- it 'resolves the value' do
61
- expect {
62
- resolved_value
63
- }.to raise_error(StackMaster::ParameterResolvers::StackOutput::StackNotFound)
64
- end
65
- end
66
-
67
- context "the output doesn't exist" do
68
- let(:outputs) { [] }
69
-
70
- it 'resolves the value' do
71
- expect {
72
- resolved_value
73
- }.to raise_error(StackMaster::ParameterResolvers::StackOutput::StackOutputNotFound)
74
- end
75
- end
76
- end
77
-
78
- context 'when given a valid string value including region' do
79
- let(:value) { 'us-east-1:my-stack/MyOutput' }
80
- let(:stacks) { [{ stack_name: 'my-stack', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs}] }
81
- let(:outputs) { [] }
82
-
83
- before do
84
- allow(Aws::CloudFormation::Client).to receive(:new).and_return(cf)
85
- cf.stub_responses(:describe_stacks, stacks: stacks)
86
- end
87
-
88
- context 'the stack and output exist' do
89
- let(:outputs) { [{output_key: 'MyOutput', output_value: 'myresolvedvalue'}] }
90
-
91
- it 'resolves the value' do
92
- expect(resolved_value).to eq 'myresolvedvalue'
93
- end
94
-
95
- context 'the stack and output exist in a different region with the same name' do
96
- let(:value_in_region_alias) { 'global:my-stack/MyOutput' }
97
- let(:value_in_region_2) { 'ap-southeast-2:my-stack/MyOutput' }
98
- let(:outputs_in_region_2) { [{output_key: 'MyOutput', output_value: 'myresolvedvalue2'}] }
99
- let(:stacks_in_region_2) { [{ stack_name: 'my-stack', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs_in_region_2}] }
100
-
101
- before do
102
- cf.stub_responses(
103
- :describe_stacks,
104
- { stacks: stacks },
105
- { stacks: stacks_in_region_2 }
106
- )
107
- allow(config).to receive(:unalias_region) do |aliased_region|
108
- if aliased_region == 'global'
109
- 'us-east-1'
110
- else
111
- aliased_region
112
- end
113
- end
114
- end
115
-
116
- it 'resolves the value to the right region' do
117
- resolver.resolve(value)
118
- expect(resolver.resolve(value_in_region_2)).to eq 'myresolvedvalue2'
119
- end
120
-
121
- it 'resolves to the same region if it is an alias' do
122
- expect(resolver.resolve(value_in_region_alias)).to eq 'myresolvedvalue'
123
- end
124
- end
125
- end
126
- end
127
- end