-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Add root_template_path to nested stack #3237
Changes from 14 commits
7a8ea9c
e5fece4
3d00af3
483e477
8849327
f47f839
8329ccf
8af007e
197e05e
cdcfd26
7d82b4d
b0ab349
952617d
b855880
63da534
ae8718e
0722e13
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ def __init__( | |
template_dict: Dict, | ||
parameter_overrides: Optional[Dict] = None, | ||
global_parameter_overrides: Optional[Dict] = None, | ||
root_template_dir: Optional[str] = None, | ||
): | ||
""" | ||
Initialize the class with SAM template data. The SAM template passed to this provider is assumed | ||
|
@@ -43,6 +44,7 @@ def __init__( | |
to get substituted within the template | ||
:param dict global_parameter_overrides: Optional dictionary of values for SAM template global parameters that | ||
might want to get substituted within the template and all its child templates | ||
:param str root_template_dir: Optional directory of root SAM Template. | ||
""" | ||
|
||
self._template_file = template_file | ||
|
@@ -53,6 +55,7 @@ def __init__( | |
) | ||
self._resources = self._template_dict.get("Resources", {}) | ||
self._global_parameter_overrides = global_parameter_overrides | ||
self._root_template_dir = root_template_dir | ||
|
||
LOG.debug("%d stacks found in the template", len(self._resources)) | ||
|
||
|
@@ -109,11 +112,19 @@ def _extract_stacks(self) -> None: | |
try: | ||
if resource_type == SamLocalStackProvider.SERVERLESS_APPLICATION: | ||
stack = SamLocalStackProvider._convert_sam_application_resource( | ||
self._template_file, self._stack_path, name, resource_properties | ||
self._template_file, | ||
self._stack_path, | ||
name, | ||
resource_properties, | ||
root_template_dir=self._root_template_dir, | ||
) | ||
if resource_type == SamLocalStackProvider.CLOUDFORMATION_STACK: | ||
stack = SamLocalStackProvider._convert_cfn_stack_resource( | ||
self._template_file, self._stack_path, name, resource_properties | ||
self._template_file, | ||
self._stack_path, | ||
name, | ||
resource_properties, | ||
root_template_dir=self._root_template_dir, | ||
) | ||
except RemoteStackLocationNotSupported: | ||
self.remote_stack_full_paths.append(get_full_path(self._stack_path, name)) | ||
|
@@ -129,6 +140,7 @@ def _convert_sam_application_resource( | |
stack_path: str, | ||
name: str, | ||
resource_properties: Dict, | ||
root_template_dir: Optional[str] = None, | ||
global_parameter_overrides: Optional[Dict] = None, | ||
) -> Optional[Stack]: | ||
location = resource_properties.get("Location") | ||
|
@@ -142,7 +154,7 @@ def _convert_sam_application_resource( | |
if location.startswith("file://"): | ||
location = unquote(urlparse(location).path) | ||
else: | ||
location = SamLocalStackProvider.normalize_resource_path(template_file, location) | ||
location = SamLocalStackProvider.normalize_resource_path(template_file, location, root_template_dir) | ||
|
||
return Stack( | ||
parent_stack_path=stack_path, | ||
|
@@ -151,7 +163,7 @@ def _convert_sam_application_resource( | |
parameters=SamLocalStackProvider.merge_parameter_overrides( | ||
resource_properties.get("Parameters", {}), global_parameter_overrides | ||
), | ||
template_dict=get_template_data(location), | ||
template_dict=get_template_data(location, root_template_dir), | ||
) | ||
|
||
@staticmethod | ||
|
@@ -160,6 +172,7 @@ def _convert_cfn_stack_resource( | |
stack_path: str, | ||
name: str, | ||
resource_properties: Dict, | ||
root_template_dir: Optional[str] = None, | ||
global_parameter_overrides: Optional[Dict] = None, | ||
) -> Optional[Stack]: | ||
template_url = resource_properties.get("TemplateURL") | ||
|
@@ -175,7 +188,7 @@ def _convert_cfn_stack_resource( | |
if template_url.startswith("file://"): | ||
template_url = unquote(urlparse(template_url).path) | ||
else: | ||
template_url = SamLocalStackProvider.normalize_resource_path(template_file, template_url) | ||
template_url = SamLocalStackProvider.normalize_resource_path(template_file, template_url, root_template_dir) | ||
|
||
return Stack( | ||
parent_stack_path=stack_path, | ||
|
@@ -184,7 +197,7 @@ def _convert_cfn_stack_resource( | |
parameters=SamLocalStackProvider.merge_parameter_overrides( | ||
resource_properties.get("Parameters", {}), global_parameter_overrides | ||
), | ||
template_dict=get_template_data(template_url), | ||
template_dict=get_template_data(template_url, root_template_dir), | ||
) | ||
|
||
@staticmethod | ||
|
@@ -194,6 +207,7 @@ def get_stacks( | |
name: str = "", | ||
parameter_overrides: Optional[Dict] = None, | ||
global_parameter_overrides: Optional[Dict] = None, | ||
root_template_dir: Optional[str] = None, | ||
) -> Tuple[List[Stack], List[str]]: | ||
""" | ||
Recursively extract stacks from a template file. | ||
|
@@ -212,15 +226,16 @@ def get_stacks( | |
global_parameter_overrides: Optional[Dict] | ||
Optional dictionary of values for SAM template global parameters | ||
that might want to get substituted within the template and its child templates | ||
|
||
root_template_dir: str | ||
Optional directory of root SAM Template. By default it is None unless we pass in a value. | ||
Returns | ||
------- | ||
stacks: List[Stack] | ||
The list of stacks extracted from template_file | ||
remote_stack_full_paths : List[str] | ||
The list of full paths of detected remote stacks | ||
""" | ||
template_dict = get_template_data(template_file) | ||
template_dict = get_template_data(template_file, root_template_dir) | ||
Comment on lines
-223
to
+238
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to provide There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently it is used in a few other places including intrinsics resolver. I prefer not changing that part. Ideally as Chris said, we can get rid of all |
||
stacks = [ | ||
Stack( | ||
stack_path, | ||
|
@@ -233,7 +248,12 @@ def get_stacks( | |
remote_stack_full_paths: List[str] = [] | ||
|
||
current = SamLocalStackProvider( | ||
template_file, stack_path, template_dict, parameter_overrides, global_parameter_overrides | ||
template_file, | ||
stack_path, | ||
template_dict, | ||
parameter_overrides, | ||
global_parameter_overrides, | ||
root_template_dir, | ||
) | ||
remote_stack_full_paths.extend(current.remote_stack_full_paths) | ||
|
||
|
@@ -244,6 +264,7 @@ def get_stacks( | |
child_stack.name, | ||
child_stack.parameters, | ||
global_parameter_overrides, | ||
root_template_dir=root_template_dir, | ||
) | ||
stacks.extend(stacks_in_child) | ||
remote_stack_full_paths.extend(remote_stack_full_paths_in_child) | ||
|
@@ -290,7 +311,7 @@ def merge_parameter_overrides( | |
return merged_parameter_overrides | ||
|
||
@staticmethod | ||
def normalize_resource_path(stack_file_path: str, path: str) -> str: | ||
def normalize_resource_path(stack_file_path: str, path: str, root_template_dir: Optional[str] = None) -> str: | ||
""" | ||
Convert resource paths found in nested stack to ones resolvable from root stack. | ||
For example, | ||
|
@@ -327,6 +348,8 @@ def normalize_resource_path(stack_file_path: str, path: str) -> str: | |
The file path of the stack containing the resource | ||
path | ||
the raw path read from the template dict | ||
root_template_dir | ||
Optional directory of root SAM Template | ||
|
||
Returns | ||
------- | ||
|
@@ -344,4 +367,7 @@ def normalize_resource_path(stack_file_path: str, path: str) -> str: | |
# absolute paths are not robust as relative paths. So here prefer to use relative path. | ||
stack_file_path = os.path.relpath(os.path.realpath(stack_file_path)) | ||
|
||
if root_template_dir: | ||
return os.path.relpath(os.path.join(os.path.dirname(stack_file_path), path), root_template_dir) | ||
|
||
return os.path.normpath(os.path.join(os.path.dirname(stack_file_path), path)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1082,5 +1082,8 @@ def test_must_pass_custom_region(self, get_stacks_mock): | |
invoke_context = InvokeContext("template_file", aws_region="my-custom-region") | ||
invoke_context._get_stacks() | ||
get_stacks_mock.assert_called_with( | ||
"template_file", parameter_overrides=None, global_parameter_overrides={"AWS::Region": "my-custom-region"} | ||
"template_file", | ||
parameter_overrides=None, | ||
root_template_dir=os.getcwd(), | ||
global_parameter_overrides={"AWS::Region": "my-custom-region"}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you put a comment at line 1087 explaining a little bit why it is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! |
||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way to do this without requiring multiple variables to specify a single path?
e.g. in one location make the path absolute, and pass that around, so that callees just read from the path without caring whether it's absolute or relative
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that is possible and useful. It needs a relative larger refactoring since currently we have a few places doing path checking and converting. I'd say it's out of scope for this bug and we can do this in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any way to reduce the number of places where these path modifications are done?
It's already somewhat confusing as for example
normalize_resource_path
already does some path changes, but then further changes are done here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed elsewhere:
normalize_resource_path
no longer converts to absolute path only since a bug was discovered. Agreed to add comment explaining the context.