8000 Refactor CFn conditions & mappings by dominikschubert · Pull Request #8546 · localstack/localstack · GitHub
[go: up one dir, main page]

Skip to content

Refactor CFn conditions & mappings #8546

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

Merged
merged 14 commits into from
Jun 28, 2023
Merged

Conversation

dominikschubert
Copy link
Member
@dominikschubert dominikschubert commented Jun 22, 2023

Changes

  • Move default resource property generation to LegacyResourceProvider
  • Remove mappings from Stack.resources for a clearer data flow / future restructuring
  • Explore/fix handling of intrinsic conditions functions & AWS::NoValue handling and add corresponding tests

@dominikschubert dominikschubert self-assigned this Jun 22, 2023
@dominikschubert dominikschubert added the semver: patch Non-breaking changes which can be included in patch releases label Jun 22, 2023
@github-actions
Copy link
github-actions bot commented Jun 22, 2023

LocalStack Community integration with Pro

       2 files         2 suites   1h 30m 49s ⏱️
2 164 tests 1 829 ✔️ 335 💤 0
2 165 runs  1 829 ✔️ 336 💤 0

Results for commit 79aeb73.

♻️ This comment has been updated with latest results.

@coveralls
Copy link
coveralls commented Jun 22, 2023

Coverage Status

coverage: 82.581% (-0.1%) from 82.725% when pulling 79aeb73 on refactor-cfn-conditions into 7e1346e on master.

@dominikschubert dominikschubert marked this pull request as ready for review June 22, 2023 15:15
@dominikschubert dominikschubert force-pushed the refactor-cfn-conditions branch from 9c49445 to 4ed3175 Compare June 26, 2023 05:10
@dominikschubert dominikschubert force-pushed the refactor-cfn-conditions branch from 4ed3175 to 79aeb73 Compare June 26, 2023 22:50
@dominikschubert dominikschubert requested a review from whummer June 27, 2023 12:05
Copy link
Member
@whummer whummer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, awesome to see the ongoing refactorings and enhancements in the template deployer. 8000 Love the depth of test coverage with the additional snapshot tests for different edge/error cases! 🚀

raise Exception(
f"Cannot resolve fn::FindInMap: {value[keys_list[0]]} {list(resources.keys())}"
f"Cannot find Mapping with ID {mapping_id} for Fn::FindInMap: {value[keys_list[0]]} {list(resources.keys())}" # TODO: verify
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
f"Cannot find Mapping with ID {mapping_id} for Fn::FindInMap: {value[keys_list[0]]} {list(resources.keys())}" # TODO: verify
f"Cannot find Mapping with ID {mapping_id} for Fn::FindInMap: {value[keys_list[0]]} {list(mappings.keys())}" # TODO: verify

if ref is None:
msg = 'Unable to resolve Ref for resource "%s" (yet)' % value["Ref"]
LOG.debug("%s - %s", msg, resources.get(value["Ref"]) or set(resources.keys()))
raise DependencyNotYetSatisfied(resource_ids=value["Ref"], message=msg)
ref = resolve_refs_recursively(stack_name, resources, ref)
ref = resolve_refs_recursively(stack_name, resources, mappings, ref)
return ref

if stripped_fn_lower == "getatt":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit (unrelated to this PR): You probably have this on your refactoring list anyway, but I feel like we could introduce proper class abstractions for the different intrinsic functions at some point, instead of the if branches below. :) 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that will be a whole intrinsic function rework. Unfortunately we're not quite there yet were we can replace the intrinsic function resolving. The idea we had here was to build a sort of "hydrated" stack that contains the whole dependency graph and a somwhat "rich" API to navigate it & resolve refs, etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current approach is also a bit of a problem because we allow things that we shouldn't. A lot of sections / Intrinsic functions only allow a subset of other intrinsic functions to be contained in their fields, which we currently can't easily model with this construct.


return result.get(key)
return selected_map.get(first_level_attribute).get(second_level_attribute)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Not sure if we want to hedge against lookup errors here, if the first level attribute is not contained in the map?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As one of the tests shows, we should actually fail much harder than we currently do 😅 CloudFormation will immediately block the execute_changeset / create stack call while we still silently fail

@@ -450,33 +448,44 @@ def _resolve_refs_recursively(stack_name, resources, value: dict | list | str |
item_to_sub[1].update(attr_refs)

for key, val in item_to_sub[1].items():
val = resolve_refs_recursively(stack_name, resources, val)
val = resolve_refs_recursively(stack_name, resources, mappings, val)
Copy link
Member
@whummer whummer Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General observation / nit: With the various refactorings going on right now, it seems a bit brittle to rely mostly on positional args. Technically it should be highlighted by the IDE if incorrect param types are passed to a function, but wondering if we could sprinkle in a few keyword args, to reduce the surface area of potentially incorrect parameter passing. 🤷

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! That's something I want to start doing (forcing kwargs usage instead of position arguments).

Technically it should be highlighted by the IDE if incorrect param types are passed to a function
In practice that hasn't worked out well unfortunately, which is why I'm also of the opinion that kwargs are usually to be preferred where possible.

It's extremely hard to refactor with positional args only especially since most of the GenericBaseModel implementations were using the signatures very inconsistently

Comment on lines +463 to +464
# TODO: ??
mapping_id = resolve_ref(stack_name, resources, mappings, mapping_id["Ref"], "Ref")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a bit of context for the ?? here: I'm just not a fan of using resolve_ref here (because not all refs here are valid) in the long term but for now its fine.

@dominikschubert dominikschubert merged commit bee5f76 into master Jun 28, 2023
@dominikschubert dominikschubert deleted the refactor-cfn-conditions branch June 28, 2023 08:14
@dfangl dfangl added this to the 2.2 milestone Jul 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver: patch Non-breaking changes which can be included in patch releases
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0