-
Notifications
You must be signed in to change notification settings - Fork 0
Fix: CFn: mappings with references #2
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
base: master
Are you sure you want to change the base?
Changes from all commits
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 |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class TemplateError(RuntimeError): | ||
""" | ||
Error thrown on a programming error from the user | ||
""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
from typing import Any | ||
|
||
from localstack.services.cloudformation.deployment_utils import PLACEHOLDER_AWS_NO_VALUE | ||
from localstack.services.cloudformation.engine.errors import TemplateError | ||
from localstack.utils.urls import localstack_host | ||
|
||
AWS_URL_SUFFIX = localstack_host().host # value is "amazonaws.com" in real AWS | ||
|
@@ -181,7 +182,52 @@ def resolve_condition( | |
) | ||
case "Fn::FindInMap": | ||
map_name, top_level_key, second_level_key = v | ||
return mappings[map_name][top_level_key][second_level_key] | ||
if isinstance(map_name, dict) and "Ref" in map_name: | ||
ref_name = map_name["Ref"] | ||
param = parameters.get(ref_name) | ||
if not param: | ||
raise TemplateError( | ||
f"Invalid reference: '{ref_name}' does not exist in parameters: '{parameters}'" | ||
) | ||
map_name = param.get("ResolvedValue") or param.get("ParameterValue") | ||
|
||
if isinstance(top_level_key, dict) and "Ref" in top_level_key: | ||
ref_name = top_level_key["Ref"] | ||
param = parameters.get(ref_name) | ||
if not param: | ||
raise TemplateError( | ||
f"Invalid reference: '{ref_name}' does not exist in parameters: '{parameters}'" | ||
) | ||
top_level_key = param.get("ResolvedValue") or param.get("ParameterValue") | ||
|
||
if isinstance(second_level_key, dict) and "Ref" in second_level_key: | ||
ref_name = second_level_key["Ref"] | ||
param = parameters.get(ref_name) | ||
if not param: | ||
raise TemplateError( | ||
f"Invalid reference: '{ref_name}' does not exist in parameters: '{parameters}'" | ||
) | ||
second_level_key = param.get("ResolvedValue") or param.get("ParameterValue") | ||
|
||
mapping = mappings.get(map_name) | ||
if not mapping: | ||
raise TemplateError( | ||
f"Invalid reference: '{map_name}' could not be found in the template mappings: '{list(mappings.keys())}'" | ||
) | ||
|
||
top_level_map = mapping.get(top_level_key) | ||
if not top_level_map: | ||
raise TemplateError( | ||
f"Invalid reference: '{top_level_key}' could not be found in the '{map_name}' mapping: '{list(mapping.keys())}'" | ||
) | ||
|
||
value = top_level_map.get(second_level_key) | ||
if not value: | ||
raise TemplateError( | ||
f"Invalid reference: '{second_level_key}' could not be found in the '{top_level_key}' mapping: '{top_level_map}'" | ||
) | ||
Comment on lines
+224
to
+228
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. style: Consider using .get() with a default value instead of checking for None |
||
|
||
return value | ||
case "Fn::If": | ||
if_condition_name, true_branch, false_branch = v | ||
if resolve_condition( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -477,6 +477,7 @@ def deploy_loop( | |
context = {**payload["callbackContext"], **event.custom_context} | ||
payload["callbackContext"] = context | ||
payload["requestData"]["resourceProperties"] = event.resource_model | ||
resource["Properties"] = event.resource_model | ||
Comment on lines
477
to
+480
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. style: Consider using a more descriptive variable name instead of 'context' |
||
|
||
if current_iteration == 0: | ||
time.sleep(0) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
Resources: | ||
MyLambdaFunction: | ||
Type: AWS::Lambda::Function | ||
Properties: | ||
FunctionName: testFunction | ||
Handler: index.handler | ||
Runtime: python3.8 | ||
Role: !GetAtt LambdaExecutionRole.Arn | ||
Code: | ||
S3Bucket: non-existent-bucket-name # Invalid S3 bucket that does not exist | ||
S3Key: non-existent-key.zip | ||
|
||
LambdaExecutionRole: | ||
Type: AWS::IAM::Role | ||
Properties: | ||
RoleName: LambdaExecutionRole | ||
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. style: Using a hardcoded RoleName may cause issues with multiple deployments or updates. Consider using a dynamic naming strategy |
||
AssumeRolePolicyDocument: | ||
Version: '2012-10-17' | ||
Statement: | ||
- Effect: Allow | ||
Principal: | ||
Service: lambda.amazonaws.com | ||
Action: sts:AssumeRole | ||
Policies: | ||
- PolicyName: LambdaBasicExecution | ||
PolicyDocument: | ||
Version: '2012-10-17' | ||
Statement: | ||
- Effect: Allow | ||
Action: | ||
- logs:CreateLogGroup | ||
- logs:CreateLogStream | ||
- logs:PutLogEvents | ||
Resource: arn:aws:logs:*:*:* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
AWSTemplateFormatVersion: '2010-09-09' | ||
Parameters: | ||
TemplateUri: | ||
Type: String | ||
|
||
Resources: | ||
ChildStack: | ||
Type: AWS::CloudFormation::Stack | ||
Properties: | ||
TemplateURL: !Ref TemplateUri | ||
|
||
Outputs: | ||
BucketStackId: | ||
Value: !Ref ChildStack | ||
Comment on lines
+13
to
+14
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. style: Consider adding a description for this output to improve template readability. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
Mappings: | ||
MyMap: | ||
A: | ||
value: "true" | ||
C: | ||
value: "false" | ||
|
||
Conditions: | ||
MyCondition: !Equals | ||
- !FindInMap [ !Ref MapName, !Ref MapKey, value ] | ||
- "true" | ||
|
||
Parameters: | ||
MapName: | ||
Type: String | ||
|
||
MapKey: | ||
Type: String | ||
|
||
TopicName: | ||
Type: String | ||
|
||
Resources: | ||
MyTopic: | ||
Type: AWS::SNS::Topic | ||
Properties: | ||
TopicName: !Ref TopicName | ||
Condition: MyCondition | ||
|
||
Dummy: | ||
Type: AWS::SNS::Topic | ||
|
||
Outputs: | ||
TopicArn: | ||
Value: !Ref MyTopic | ||
|
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.
style: Consider extracting this Ref resolution logic into a separate function to reduce code duplication