Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Resolves #1388] Handle failures gracefully in stack outputs #1391

Merged
merged 15 commits into from
Feb 8, 2024
60 changes: 46 additions & 14 deletions sceptre/resolvers/stack_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

from botocore.exceptions import ClientError

from sceptre.exceptions import DependencyStackMissingOutputError, StackDoesNotExistError
from sceptre.exceptions import (
DependencyStackMissingOutputError,
StackDoesNotExistError,
SceptreException,
)

from sceptre.helpers import normalise_path, sceptreise_path
from sceptre.resolvers import Resolver

Expand Down Expand Up @@ -108,7 +113,13 @@ def setup(self):
"""
Adds dependency to a Stack.
"""
dep_stack_name, self.output_key = self.argument.split("::")
try:
dep_stack_name, self.output_key = self.argument.split("::")
except ValueError as err:
raise SceptreException(
"!stack_output arg should match STACK_NAME::OUTPUT_KEY"
) from err

self.dependency_stack_name = sceptreise_path(normalise_path(dep_stack_name))
self.stack.dependencies.append(self.dependency_stack_name)

Expand All @@ -120,7 +131,6 @@ def resolve(self):
:rtype: str
"""
self.logger.debug("Resolving Stack output: {0}".format(self.argument))

friendly_stack_name = self.dependency_stack_name.replace(TEMPLATE_EXTENSION, "")

stack = next(
Expand Down Expand Up @@ -163,21 +173,43 @@ def resolve(self):
"""
self.logger.debug("Resolving external Stack output: {0}".format(self.argument))

profile = None
region = None
sceptre_role = None
arguments = shlex.split(self.argument)
alex-harvey-z3q marked this conversation as resolved.
Show resolved Hide resolved

if not arguments:
message = "!stack_output_external requires at least one argument"
raise SceptreException(message)

stack_argument = arguments[0]
alex-harvey-z3q marked this conversation as resolved.
Show resolved Hide resolved
stack_args = iter(stack_argument.split("::"))

try:
dependency_stack_name = next(stack_args)
output_key = next(stack_args)

except StopIteration as err:
message = "!stack_output_external arg should match STACK_NAME::OUTPUT_KEY"
raise SceptreException(message) from err

profile = region = sceptre_role = None

if len(arguments) > 1:
alex-harvey-z3q marked this conversation as resolved.
Show resolved Hide resolved
extra_args = arguments[1].split("::", 2)
profile, region, sceptre_role = extra_args + (3 - len(extra_args)) * [None]
extra_args = iter(arguments[1].split("::"))

profile = next(extra_args, None)
region = next(extra_args, None)
sceptre_role = next(extra_args, None)

try:
next(extra_args)
message = (
"!stack_output_external second arg should be "
"in the format 'PROFILE[::REGION[::SCEPTRE_ROLE]]'"
)
raise SceptreException(message)

except StopIteration:
pass

dependency_stack_name, output_key = stack_argument.split("::")
return self._get_output_value(
dependency_stack_name,
output_key,
profile or None,
region or None,
sceptre_role or None,
dependency_stack_name, output_key, profile, region, sceptre_role
)
11 changes: 9 additions & 2 deletions tests/test_resolvers/test_stack_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from sceptre.exceptions import DependencyStackMissingOutputError
from sceptre.exceptions import StackDoesNotExistError
from sceptre.exceptions import SceptreException

from botocore.exceptions import ClientError

Expand Down Expand Up @@ -58,7 +59,10 @@ def test_resolver__badly_formatted(self, mock_get_output_value):

stack_output_resolver = StackOutput("not_a_valid_stack_output", stack)

with pytest.raises(ValueError, match="not enough values to unpack"):
with pytest.raises(
SceptreException,
match="!stack_output arg should match STACK_NAME::OUTPUT_KEY",
):
stack_output_resolver.setup()

@patch("sceptre.resolvers.stack_output.StackOutput._get_output_value")
Expand Down Expand Up @@ -191,7 +195,10 @@ def test_resolve__badly_formatted(self, mock_get_output_value):
"not_a_valid_stack_output", stack
)

with pytest.raises(ValueError, match="not enough values to unpack"):
with pytest.raises(
SceptreException,
match="!stack_output_external arg should match STACK_NAME::OUTPUT_KEY",
):
stack_output_external_resolver.resolve()

@patch("sceptre.resolvers.stack_output.StackOutputExternal._get_output_value")
Expand Down
Loading