stack_master 1.5.0 → 1.6.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 (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