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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions localstack/services/cloudformation/engine/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def __init__(
self.events = []
# list of stack change sets
self.change_sets = []
# self.evaluated_conditions = {}

def set_resolved_parameters(self, resolved_parameters: dict[str, Parameter]):
self.resolved_parameters = resolved_parameters
Expand Down Expand Up @@ -247,21 +248,14 @@ def resources(self): # TODO: not actually resources, split apart
{k: map_to_legacy_structure(k, v) for k, v in self.resolved_parameters.items()}
)

# TODO: conditions and mappings don't really belong here and should be handled separately
# TODO: conditions don't really belong here and should be handled separately
for name, value in self.conditions.items():
if name not in result:
result[name] = {
"Type": "Parameter",
"LogicalResourceId": name,
"Properties": {"Value": value},
}
for name, value in self.mappings.items():
if name not in result:
result[name] = {
"Type": "Parameter",
"LogicalResourceId": name,
"Properties": {"Value": value},
}

return result

Expand Down
189 changes: 98 additions & 91 deletions localstack/services/cloudformation/engine/template_deployer.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ def template_to_json(template: str) -> str:


# TODO: consider moving to transformers.py as well
def transform_template(template: dict, parameters: list, stack_name: str, resources: dict) -> dict:
def transform_template(
template: dict, parameters: list, stack_name: str, resources: dict, mappings: dict
) -> dict:
result = dict(template)

# apply 'Fn::Transform' intrinsic functions (note: needs to be applied before global
# transforms below, as some utils - incl samtransformer - expect them to be resolved already)
result = apply_transform_intrinsic_functions(result, stack_name, resources)
result = apply_transform_intrinsic_functions(result, stack_name, resources, mappings)

# apply global transforms
transformations = format_transforms(result.get("Transform", []))
Expand Down
6 changes: 4 additions & 2 deletions localstack/services/cloudformation/engine/transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ def transform(self, parameters: dict) -> TransformResult:
transformers: Dict[str, Type] = {"AWS::Include": AwsIncludeTransformer}


def apply_transform_intrinsic_functions(template: dict, stack_name: str, resources: dict) -> dict:
def apply_transform_intrinsic_functions(
template: dict, stack_name: str, resources: dict, mappings: dict
) -> dict:
"""Resolve constructs using the 'Fn::Transform' intrinsic function."""
from localstack.services.cloudformation.engine.template_deployer import resolve_refs_recursively

Expand All @@ -51,7 +53,7 @@ def _visit(obj, **_):
if transformer_class:
transformer = transformer_class()
parameters = transform.get("Parameters") or {}
parameters = resolve_refs_recursively(stack_name, resources, parameters)
parameters = resolve_refs_recursively(stack_name, resources, mappings, parameters)
return transformer.transform(parameters)
return obj

Expand Down
27 changes: 23 additions & 4 deletions localstack/services/cloudformation/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def create_stack(self, context: RequestContext, request: CreateStackInput) -> Cr
"Requires capabilities : [CAPABILITY_AUTO_EXPAND]"
)

# resolve stack parameters
new_parameters: dict[str, Parameter] = param_resolver.convert_stack_parameters_to_dict(
request.get("Parameters")
)
Expand All @@ -199,11 +200,16 @@ def create_stack(self, context: RequestContext, request: CreateStackInput) -> Cr
old_parameters={},
)

# handle conditions
stack = Stack(request, template)

try:
template = template_preparer.transform_template(
template, list(resolved_parameters.values()), stack.stack_name, stack.resources
template,
list(resolved_parameters.values()),
stack.stack_name,
stack.resources,
stack.mappings,
)
except FailedTransformationException as e:
stack.add_stack_event(
Expand Down Expand Up @@ -283,7 +289,11 @@ def update_stack(

try:
template = template_preparer.transform_template(
template, list(resolved_parameters.values()), stack.stack_name, stack.resources
template,
list(resolved_parameters.values()),
stack.stack_name,
stack.resources,
stack.mappings,
)
except FailedTransformationException as e:
stack.add_stack_event(
Expand Down Expand Up @@ -506,7 +516,7 @@ def create_change_set(
)
raise ValidationError(msg)

# apply template transformations
# resolve parameters
new_parameters: dict[str, Parameter] = param_resolver.convert_stack_parameters_to_dict(
request.get("Parameters")
)
Expand All @@ -526,15 +536,24 @@ def create_change_set(
temp_stack = Stack(req_params_copy, template)
temp_stack.set_resolved_parameters(resolved_parameters)

# TODO: everything below should be async
# apply template transformations
transformed_template = template_preparer.transform_template(
template, parameters, stack_name=temp_stack.stack_name, resources=temp_stack.resources
template,
parameters,
stack_name=temp_stack.stack_name,
resources=temp_stack.resources,
mappings=temp_stack.mappings,
)

# create change set for the stack and apply changes
change_set = StackChangeSet(stack, req_params, transformed_template)
# only set parameters for the changeset, then switch to stack on execute_change_set
change_set.set_resolved_parameters(resolved_parameters)

# TODO: evaluate conditions
# change_set.set_resolved_conditions(resolved_conditions)

deployer = template_deployer.TemplateDeployer(change_set)
changes = deployer.construct_changes(
stack,
Expand Down
8 changes: 7 additions & 1 deletion localstack/services/cloudformation/resource_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,12 +397,13 @@ def update(self, request: ResourceRequest[Properties]) -> ProgressEvent[Properti
request.logical_resource_id,
)
# TODO: should not really claim the update was successful, but the
# API does not really let us signal this in any other way.
# API does not really let us signal this in any other way.
return ProgressEvent(
status=OperationStatus.SUCCESS, resource_model=request.desired_state
)

LOG.info("Updating resource %s of type %s", request.logical_resource_id, self.resource_type)

resource_provider.update_resource(
self.all_resources[request.logical_resource_id],
stack_name=request.stack_name,
Expand Down Expand Up @@ -431,6 +432,11 @@ def create_or_delete(self, request: ResourceRequest[Properties]) -> ProgressEven
},
region_name=request.region_name,
)
# TODO: only really necessary for the create and update operation
resource_provider.add_defaults(
self.all_resources[request.logical_resource_id], request.stack_name
)

func_details = resource_provider.get_deploy_templates()
# TODO: be less strict about the return value of func_details
LOG.debug(
Expand Down
Empty file.
Loading
0