From 6d9d176aebf87b09cd75183f2bcbc932c0c7360c Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Mon, 30 Jan 2023 22:35:47 +0100 Subject: [PATCH 1/9] Add support for FindInMap default --- cloudformation/intrinsics.go | 26 +++++++++++++++++++++----- goformation_test.go | 9 ++++++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index 552268f8f4..c8fa3cf5d0 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -72,6 +72,18 @@ func str3Wrap(fn func(interface{}, interface{}, interface{}) string) intrinsics. } } +func str4Wrap(fn func(interface{}, interface{}, interface{}, interface{}) string) intrinsics.IntrinsicHandler { + return func(name string, input interface{}, template interface{}) interface{} { + if arr, ok := input.([]interface{}); ok { + if len(arr) != 4 { + return nil + } + return fn(arr[0], arr[1], arr[2], arr[3]) + } + return nil + } +} + func str2AWrap(fn func(interface{}, []string) string) intrinsics.IntrinsicHandler { return func(name string, input interface{}, template interface{}) interface{} { if arr, ok := input.([]interface{}); ok { @@ -107,7 +119,7 @@ var EncoderIntrinsics = map[string]intrinsics.IntrinsicHandler{ "Fn::If": str3Wrap(If), "Fn::Not": strAWrap(Not), "Fn::Or": strAWrap(Or), - "Fn::FindInMap": str3Wrap(FindInMap), + "Fn::FindInMap": str4Wrap(FindInMap), "Fn::GetAtt": strSplit2Wrap(GetAtt), "Fn::GetAZs": strWrap(GetAZs), "Fn::ImportValue": strWrap(ImportValue), @@ -226,12 +238,16 @@ func CIDRPtr(ipBlock, count, cidrBits interface{}) *string { } // FindInMap returns the value corresponding to keys in a two-level map that is declared in the Mappings section. -func FindInMap(mapName, topLevelKey, secondLevelKey interface{}) string { - return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q ] }`, mapName, topLevelKey, secondLevelKey)) +func FindInMap(mapName, topLevelKey, secondLevelKey, defaultValue interface{}) string { + if defaultValue == nil { + return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q] }`, mapName, topLevelKey, secondLevelKey)) + } else { + return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q, { "DefaultValue": %q }] }`, mapName, topLevelKey, secondLevelKey, defaultValue)) + } } -func FindInMapPtr(mapName, topLevelKey, secondLevelKey interface{}) *string { - return String(FindInMap(mapName, topLevelKey, secondLevelKey)) +func FindInMapPtr(mapName, topLevelKey, secondLevelKey, defaultValue interface{}) *string { + return String(FindInMap(mapName, topLevelKey, secondLevelKey, defaultValue)) } // If returns one value if the specified condition evaluates to true and another value if the specified condition evaluates to false. Currently, AWS CloudFormation supports the Fn::If intrinsic function in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template. You can use the AWS::NoValue pseudo parameter as a return value to remove the corresponding property. diff --git a/goformation_test.go b/goformation_test.go index d8366a31ab..fe730ec99d 100644 --- a/goformation_test.go +++ b/goformation_test.go @@ -1047,11 +1047,18 @@ var _ = Describe("Goformation", func() { }, { Name: "Fn::FindInMap", - Input: cloudformation.FindInMap("test-map", "test-top-level-key", "test-second-level-key"), + Input: cloudformation.FindInMap("test-map", "test-top-level-key", "test-second-level-key", nil), Expected: map[string]interface{}{ "Fn::FindInMap": []interface{}{"test-map", "test-top-level-key", "test-second-level-key"}, }, }, + { + Name: "Fn::FindInMap with DefaultValue", + Input: cloudformation.FindInMap("test-map", "test-top-level-key", "test-second-level-key", "test-default-value"), + Expected: map[string]interface{}{ + "Fn::FindInMap": []interface{}{"test-map", "test-top-level-key", "test-second-level-key", map[string]interface{}{"DefaultValue": "test-default-value"}}, + }, + }, { Name: "Fn::GetAZs", Input: cloudformation.GetAZs("test-region"), From 00bf132d47b90af8ddbfdc06ffae1b6953ab27b0 Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Tue, 31 Jan 2023 11:33:49 +0100 Subject: [PATCH 2/9] fix tests --- cloudformation/intrinsics.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index c8fa3cf5d0..c9604e482c 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -72,13 +72,17 @@ func str3Wrap(fn func(interface{}, interface{}, interface{}) string) intrinsics. } } -func str4Wrap(fn func(interface{}, interface{}, interface{}, interface{}) string) intrinsics.IntrinsicHandler { +func str3optional4Wrap(fn func(interface{}, interface{}, interface{}, interface{}) string) intrinsics.IntrinsicHandler { return func(name string, input interface{}, template interface{}) interface{} { if arr, ok := input.([]interface{}); ok { - if len(arr) != 4 { + if len(arr) == 3 { + return fn(arr[0], arr[1], arr[2], nil) + } else if len(arr) == 4 { + return fn(arr[0], arr[1], arr[2], arr[3]) + + } else { return nil } - return fn(arr[0], arr[1], arr[2], arr[3]) } return nil } @@ -119,7 +123,7 @@ var EncoderIntrinsics = map[string]intrinsics.IntrinsicHandler{ "Fn::If": str3Wrap(If), "Fn::Not": strAWrap(Not), "Fn::Or": strAWrap(Or), - "Fn::FindInMap": str4Wrap(FindInMap), + "Fn::FindInMap": str3optional4Wrap(FindInMap), "Fn::GetAtt": strSplit2Wrap(GetAtt), "Fn::GetAZs": strWrap(GetAZs), "Fn::ImportValue": strWrap(ImportValue), From 43c5ea40534bae8d7d80b1eaaad4338962d92fb1 Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Tue, 31 Jan 2023 11:37:17 +0100 Subject: [PATCH 3/9] Move to switch --- cloudformation/intrinsics.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index c9604e482c..6fefa9c8ba 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -72,17 +72,16 @@ func str3Wrap(fn func(interface{}, interface{}, interface{}) string) intrinsics. } } -func str3optional4Wrap(fn func(interface{}, interface{}, interface{}, interface{}) string) intrinsics.IntrinsicHandler { +func str3Optional4Wrap(fn func(interface{}, interface{}, interface{}, interface{}) string) intrinsics.IntrinsicHandler { return func(name string, input interface{}, template interface{}) interface{} { if arr, ok := input.([]interface{}); ok { - if len(arr) == 3 { + switch len(arr) { + case 3: return fn(arr[0], arr[1], arr[2], nil) - } else if len(arr) == 4 { + case 4: return fn(arr[0], arr[1], arr[2], arr[3]) - - } else { - return nil } + return nil } return nil } @@ -123,7 +122,7 @@ var EncoderIntrinsics = map[string]intrinsics.IntrinsicHandler{ "Fn::If": str3Wrap(If), "Fn::Not": strAWrap(Not), "Fn::Or": strAWrap(Or), - "Fn::FindInMap": str3optional4Wrap(FindInMap), + "Fn::FindInMap": str3Optional4Wrap(FindInMap), "Fn::GetAtt": strSplit2Wrap(GetAtt), "Fn::GetAZs": strWrap(GetAZs), "Fn::ImportValue": strWrap(ImportValue), From fbc8d6830c4533652c7393058fb7c515e8fb0958 Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Wed, 31 May 2023 20:15:38 +0200 Subject: [PATCH 4/9] change to list variable --- cloudformation/intrinsics.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index 6fefa9c8ba..026b207b05 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -72,16 +72,10 @@ func str3Wrap(fn func(interface{}, interface{}, interface{}) string) intrinsics. } } -func str3Optional4Wrap(fn func(interface{}, interface{}, interface{}, interface{}) string) intrinsics.IntrinsicHandler { +func strVarArgsWrap(fn func(...interface{}) string) intrinsics.IntrinsicHandler { return func(name string, input interface{}, template interface{}) interface{} { if arr, ok := input.([]interface{}); ok { - switch len(arr) { - case 3: - return fn(arr[0], arr[1], arr[2], nil) - case 4: - return fn(arr[0], arr[1], arr[2], arr[3]) - } - return nil + return fn(arr...) } return nil } @@ -122,7 +116,7 @@ var EncoderIntrinsics = map[string]intrinsics.IntrinsicHandler{ "Fn::If": str3Wrap(If), "Fn::Not": strAWrap(Not), "Fn::Or": strAWrap(Or), - "Fn::FindInMap": str3Optional4Wrap(FindInMap), + "Fn::FindInMap": strVarArgsWrap(FindInMap), "Fn::GetAtt": strSplit2Wrap(GetAtt), "Fn::GetAZs": strWrap(GetAZs), "Fn::ImportValue": strWrap(ImportValue), @@ -240,10 +234,17 @@ func CIDRPtr(ipBlock, count, cidrBits interface{}) *string { return String(CIDR(ipBlock, count, cidrBits)) } -// FindInMap returns the value corresponding to keys in a two-level map that is declared in the Mappings section. -func FindInMap(mapName, topLevelKey, secondLevelKey, defaultValue interface{}) string { +func FindInMap(args ...interface{}) string { + mapName := args[0] + topLevelKey := args[1] + secondLevelKey := args[2] + var defaultValue interface{} + if len(args) == 4 { + defaultValue = args[3] + } + if defaultValue == nil { - return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q] }`, mapName, topLevelKey, secondLevelKey)) + return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q ] }`, mapName, topLevelKey, secondLevelKey)) } else { return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q, { "DefaultValue": %q }] }`, mapName, topLevelKey, secondLevelKey, defaultValue)) } From 2a071c6ac9d90ae7d57c512483497da0fcc76ade Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Wed, 31 May 2023 20:18:30 +0200 Subject: [PATCH 5/9] update FindInMapPtr --- cloudformation/intrinsics.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index 026b207b05..b8f59abada 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -250,8 +250,8 @@ func FindInMap(args ...interface{}) string { } } -func FindInMapPtr(mapName, topLevelKey, secondLevelKey, defaultValue interface{}) *string { - return String(FindInMap(mapName, topLevelKey, secondLevelKey, defaultValue)) +func FindInMapPtr(args ...interface{}) *string { + return String(FindInMap(args)) } // If returns one value if the specified condition evaluates to true and another value if the specified condition evaluates to false. Currently, AWS CloudFormation supports the Fn::If intrinsic function in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template. You can use the AWS::NoValue pseudo parameter as a return value to remove the corresponding property. From b9eb052bbef50ca3918b0914a72e6bb2f12cb900 Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Wed, 31 May 2023 20:34:09 +0200 Subject: [PATCH 6/9] Update FindInMap --- cloudformation/intrinsics.go | 27 ++++++++++++--------------- goformation_test.go | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index b8f59abada..ce7c5d93f5 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -72,10 +72,10 @@ func str3Wrap(fn func(interface{}, interface{}, interface{}) string) intrinsics. } } -func strVarArgsWrap(fn func(...interface{}) string) intrinsics.IntrinsicHandler { +func strVarArgsWrap(fn func(string, string, string, ...string) string) intrinsics.IntrinsicHandler { return func(name string, input interface{}, template interface{}) interface{} { - if arr, ok := input.([]interface{}); ok { - return fn(arr...) + if arr, ok := input.([]string); ok && len(arr) >= 3 { + return fn(arr[0], arr[1], arr[2], arr[3:]...) } return nil } @@ -234,24 +234,21 @@ func CIDRPtr(ipBlock, count, cidrBits interface{}) *string { return String(CIDR(ipBlock, count, cidrBits)) } -func FindInMap(args ...interface{}) string { - mapName := args[0] - topLevelKey := args[1] - secondLevelKey := args[2] - var defaultValue interface{} - if len(args) == 4 { - defaultValue = args[3] +func FindInMap(mapName, topLevelKey, secondLevelKey string, defaultValue ...string) string { + var defaultVal string + if len(defaultValue) > 0 { + defaultVal = defaultValue[0] } - if defaultValue == nil { - return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q ] }`, mapName, topLevelKey, secondLevelKey)) + if defaultVal == "" { + return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ "%s", "%s", "%s" ] }`, mapName, topLevelKey, secondLevelKey)) } else { - return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q, { "DefaultValue": %q }] }`, mapName, topLevelKey, secondLevelKey, defaultValue)) + return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ "%s", "%s", "%s", { "DefaultValue": "%s" }] }`, mapName, topLevelKey, secondLevelKey, defaultVal)) } } -func FindInMapPtr(args ...interface{}) *string { - return String(FindInMap(args)) +func FindInMapPtr(mapName, topLevelKey, secondLevelKey string, defaultValue ...string) *string { + return String(FindInMap(mapName, topLevelKey, secondLevelKey, defaultValue...)) } // If returns one value if the specified condition evaluates to true and another value if the specified condition evaluates to false. Currently, AWS CloudFormation supports the Fn::If intrinsic function in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template. You can use the AWS::NoValue pseudo parameter as a return value to remove the corresponding property. diff --git a/goformation_test.go b/goformation_test.go index fe730ec99d..b636c48c3b 100644 --- a/goformation_test.go +++ b/goformation_test.go @@ -1047,7 +1047,7 @@ var _ = Describe("Goformation", func() { }, { Name: "Fn::FindInMap", - Input: cloudformation.FindInMap("test-map", "test-top-level-key", "test-second-level-key", nil), + Input: cloudformation.FindInMap("test-map", "test-top-level-key", "test-second-level-key"), Expected: map[string]interface{}{ "Fn::FindInMap": []interface{}{"test-map", "test-top-level-key", "test-second-level-key"}, }, From 107ce2beacd9a53df9f295c5486c195d44c1abd8 Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Wed, 31 May 2023 20:48:19 +0200 Subject: [PATCH 7/9] revert --- goformation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goformation_test.go b/goformation_test.go index fe730ec99d..b636c48c3b 100644 --- a/goformation_test.go +++ b/goformation_test.go @@ -1047,7 +1047,7 @@ var _ = Describe("Goformation", func() { }, { Name: "Fn::FindInMap", - Input: cloudformation.FindInMap("test-map", "test-top-level-key", "test-second-level-key", nil), + Input: cloudformation.FindInMap("test-map", "test-top-level-key", "test-second-level-key"), Expected: map[string]interface{}{ "Fn::FindInMap": []interface{}{"test-map", "test-top-level-key", "test-second-level-key"}, }, From d51e7ad7932c2c9a45fff083372f20bc30a4a3af Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Wed, 31 May 2023 20:49:39 +0200 Subject: [PATCH 8/9] revert --- cloudformation/intrinsics.go | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index ce7c5d93f5..b8f59abada 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -72,10 +72,10 @@ func str3Wrap(fn func(interface{}, interface{}, interface{}) string) intrinsics. } } -func strVarArgsWrap(fn func(string, string, string, ...string) string) intrinsics.IntrinsicHandler { +func strVarArgsWrap(fn func(...interface{}) string) intrinsics.IntrinsicHandler { return func(name string, input interface{}, template interface{}) interface{} { - if arr, ok := input.([]string); ok && len(arr) >= 3 { - return fn(arr[0], arr[1], arr[2], arr[3:]...) + if arr, ok := input.([]interface{}); ok { + return fn(arr...) } return nil } @@ -234,21 +234,24 @@ func CIDRPtr(ipBlock, count, cidrBits interface{}) *string { return String(CIDR(ipBlock, count, cidrBits)) } -func FindInMap(mapName, topLevelKey, secondLevelKey string, defaultValue ...string) string { - var defaultVal string - if len(defaultValue) > 0 { - defaultVal = defaultValue[0] +func FindInMap(args ...interface{}) string { + mapName := args[0] + topLevelKey := args[1] + secondLevelKey := args[2] + var defaultValue interface{} + if len(args) == 4 { + defaultValue = args[3] } - if defaultVal == "" { - return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ "%s", "%s", "%s" ] }`, mapName, topLevelKey, secondLevelKey)) + if defaultValue == nil { + return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q ] }`, mapName, topLevelKey, secondLevelKey)) } else { - return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ "%s", "%s", "%s", { "DefaultValue": "%s" }] }`, mapName, topLevelKey, secondLevelKey, defaultVal)) + return encode(fmt.Sprintf(`{ "Fn::FindInMap" : [ %q, %q, %q, { "DefaultValue": %q }] }`, mapName, topLevelKey, secondLevelKey, defaultValue)) } } -func FindInMapPtr(mapName, topLevelKey, secondLevelKey string, defaultValue ...string) *string { - return String(FindInMap(mapName, topLevelKey, secondLevelKey, defaultValue...)) +func FindInMapPtr(args ...interface{}) *string { + return String(FindInMap(args)) } // If returns one value if the specified condition evaluates to true and another value if the specified condition evaluates to false. Currently, AWS CloudFormation supports the Fn::If intrinsic function in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template. You can use the AWS::NoValue pseudo parameter as a return value to remove the corresponding property. From 61941fc69e2d0dbaae614dfbe8618bdeb5941b6d Mon Sep 17 00:00:00 2001 From: Marcin Rabenda Date: Wed, 7 Jun 2023 16:30:20 +0200 Subject: [PATCH 9/9] Follow 4 arguments --- cloudformation/intrinsics.go | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/cloudformation/intrinsics.go b/cloudformation/intrinsics.go index b8f59abada..2a37c534ec 100644 --- a/cloudformation/intrinsics.go +++ b/cloudformation/intrinsics.go @@ -72,10 +72,19 @@ func str3Wrap(fn func(interface{}, interface{}, interface{}) string) intrinsics. } } -func strVarArgsWrap(fn func(...interface{}) string) intrinsics.IntrinsicHandler { +func findInMapWrap(fn func(interface{}, interface{}, interface{}, ...interface{}) string) intrinsics.IntrinsicHandler { return func(name string, input interface{}, template interface{}) interface{} { if arr, ok := input.([]interface{}); ok { - return fn(arr...) + if len(arr) < 3 { + return nil + } + + mapName := arr[0] + topLevelKey := arr[1] + secondLevelKey := arr[2] + additional := arr[3:] + + return fn(mapName, topLevelKey, secondLevelKey, additional...) } return nil } @@ -116,7 +125,7 @@ var EncoderIntrinsics = map[string]intrinsics.IntrinsicHandler{ "Fn::If": str3Wrap(If), "Fn::Not": strAWrap(Not), "Fn::Or": strAWrap(Or), - "Fn::FindInMap": strVarArgsWrap(FindInMap), + "Fn::FindInMap": findInMapWrap(FindInMap), "Fn::GetAtt": strSplit2Wrap(GetAtt), "Fn::GetAZs": strWrap(GetAZs), "Fn::ImportValue": strWrap(ImportValue), @@ -234,13 +243,10 @@ func CIDRPtr(ipBlock, count, cidrBits interface{}) *string { return String(CIDR(ipBlock, count, cidrBits)) } -func FindInMap(args ...interface{}) string { - mapName := args[0] - topLevelKey := args[1] - secondLevelKey := args[2] +func FindInMap(mapName, topLevelKey, secondLevelKey interface{}, additional ...interface{}) string { var defaultValue interface{} - if len(args) == 4 { - defaultValue = args[3] + if len(additional) > 0 { + defaultValue = additional[0] } if defaultValue == nil { @@ -250,8 +256,8 @@ func FindInMap(args ...interface{}) string { } } -func FindInMapPtr(args ...interface{}) *string { - return String(FindInMap(args)) +func FindInMapPtr(mapName, topLevelKey, secondLevelKey interface{}, additional ...interface{}) *string { + return String(FindInMap(mapName, topLevelKey, secondLevelKey, additional...)) } // If returns one value if the specified condition evaluates to true and another value if the specified condition evaluates to false. Currently, AWS CloudFormation supports the Fn::If intrinsic function in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template. You can use the AWS::NoValue pseudo parameter as a return value to remove the corresponding property.