From 6f7dcda0fb87166bd1396a1c5391f9eff3a2af18 Mon Sep 17 00:00:00 2001 From: Cristopher Pinzon Date: Wed, 22 Jan 2025 15:47:16 +0100 Subject: [PATCH] fix cfn template join with noValue --- .../engine/template_deployer.py | 4 ++- .../cloudformation/test_template_engine.py | 10 ++++++ .../test_template_engine.snapshot.json | 10 ++++++ .../test_template_engine.validation.json | 3 ++ tests/aws/templates/engine/join_no_value.yml | 34 +++++++++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/aws/templates/engine/join_no_value.yml diff --git a/localstack-core/localstack/services/cloudformation/engine/template_deployer.py b/localstack-core/localstack/services/cloudformation/engine/template_deployer.py index 3180a820baf16..5a451e5171a73 100644 --- a/localstack-core/localstack/services/cloudformation/engine/template_deployer.py +++ b/localstack-core/localstack/services/cloudformation/engine/template_deployer.py @@ -420,7 +420,9 @@ def _resolve_refs_recursively( raise Exception( f"Cannot resolve CF Fn::Join {value} due to null values: {join_values}" ) - return value[keys_list[0]][0].join([str(v) for v in join_values]) + return value[keys_list[0]][0].join( + [str(v) for v in join_values if v != "__aws_no_value__"] + ) if stripped_fn_lower == "sub": item_to_sub = value[keys_list[0]] diff --git a/tests/aws/services/cloudformation/test_template_engine.py b/tests/aws/services/cloudformation/test_template_engine.py index c6da516eac01d..d039307ef5101 100644 --- a/tests/aws/services/cloudformation/test_template_engine.py +++ b/tests/aws/services/cloudformation/test_template_engine.py @@ -263,6 +263,16 @@ def test_sub_number_type(self, deploy_cfn_template): assert stack.outputs["Threshold"] == threshold assert stack.outputs["Period"] == period + @markers.aws.validated + def test_join_no_value_construct(self, deploy_cfn_template, snapshot, aws_client): + stack = deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), "../../templates/engine/join_no_value.yml" + ) + ) + + snapshot.match("join-output", stack.outputs) + class TestImports: @markers.aws.validated diff --git a/tests/aws/services/cloudformation/test_template_engine.snapshot.json b/tests/aws/services/cloudformation/test_template_engine.snapshot.json index df326dbfcbbeb..da52914bdd544 100644 --- a/tests/aws/services/cloudformation/test_template_engine.snapshot.json +++ b/tests/aws/services/cloudformation/test_template_engine.snapshot.json @@ -673,5 +673,15 @@ } } } + }, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_join_no_value_construct": { + "recorded-date": "22-01-2025, 14:01:46", + "recorded-content": { + "join-output": { + "JoinConditionalNoValue": "", + "JoinOnlyNoValue": "", + "JoinWithNoValue": "Sample" + } + } } } diff --git a/tests/aws/services/cloudformation/test_template_engine.validation.json b/tests/aws/services/cloudformation/test_template_engine.validation.json index 91f44725ce40d..e0bbb0be7e342 100644 --- a/tests/aws/services/cloudformation/test_template_engine.validation.json +++ b/tests/aws/services/cloudformation/test_template_engine.validation.json @@ -35,6 +35,9 @@ "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-west-2]": { "last_validated_date": "2024-05-09T08:33:45+00:00" }, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_join_no_value_construct": { + "last_validated_date": "2025-01-22T14:01:46+00:00" + }, "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_sub_number_type": { "last_validated_date": "2024-08-09T06:55:16+00:00" }, diff --git a/tests/aws/templates/engine/join_no_value.yml b/tests/aws/templates/engine/join_no_value.yml new file mode 100644 index 0000000000000..c974faff820f0 --- /dev/null +++ b/tests/aws/templates/engine/join_no_value.yml @@ -0,0 +1,34 @@ +Conditions: + active: !Equals [ true, true ] + inactive: !Equals [ true, false ] + +Resources: + Parameter: + Type: AWS::SSM::Parameter + Properties: + Type: String + Value: Sample + Name: commands + +Outputs: + JoinWithNoValue: + Value: + Fn::Join: + - "," + - - !GetAtt Parameter.Value + - !Ref AWS::NoValue + + JoinOnlyNoValue: + Value: + Fn::Join: + - "," + - - !Ref AWS::NoValue + + JoinConditionalNoValue: + Value: + Fn::Join: + - "," + - - Fn::If: + - active + - !Ref AWS::NoValue + - !Ref AWS::NoValue