Skip to content

Commit

Permalink
fix: convert ip_filter values into the target type (#1721)
Browse files Browse the repository at this point in the history
  • Loading branch information
byashimov authored May 13, 2024
1 parent 878fdb2 commit bf29ca8
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ nav_order: 1

## [MAJOR.MINOR.PATCH] - YYYY-MM-DD

- Fix `ip_filter`, `ip_filter_string`, and `ip_filter_object` crash when receive an unexpected type

## [4.17.0] - 2024-05-07

- Fix `aiven_kafka_connector` fails to create resource with 201 error
Expand Down
5 changes: 4 additions & 1 deletion internal/sdkprovider/userconfig/converters/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,10 @@ func flatten(kind userConfigType, name string, d *schema.ResourceData, dto map[s
prefix := fmt.Sprintf("%s.0.", key)

// Renames ip_filter to ip_filter_object
renameAliasesToTfo(kind, name, dto, d)
err := renameAliasesToTfo(kind, name, dto, d)
if err != nil {
return err
}

// Copies "create only" fields from the original config.
// Like admin_password, that is received only on POST request when service is created.
Expand Down
68 changes: 66 additions & 2 deletions internal/sdkprovider/userconfig/converters/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package converters

import (
"encoding/json"
"fmt"
"reflect"
"strings"
Expand Down Expand Up @@ -37,22 +38,85 @@ type resourceData interface {
// renameAliasesToTfo renames aliases to TF object
// Must sort keys to rename from bottom to top.
// Otherwise, might not find the deepest key if parent key is renamed
func renameAliasesToTfo(kind userConfigType, name string, dto map[string]any, d resourceData) {
func renameAliasesToTfo(kind userConfigType, name string, dto map[string]any, d resourceData) error {
prefix := userConfigKey(kind, name) + ".0."
m := getFieldMapping(kind, name)

for _, to := range sortKeys(m) {
from := m[to]

if strings.HasSuffix(to, "_string") || strings.HasSuffix(to, "_object") {
// If resource doesn't have this field, then ignores (uses original)
path := strings.ReplaceAll(to, "/", ".0.")
_, ok := d.GetOk(fmt.Sprintf("%s.0.%s", userConfigKey(kind, name), path))
_, ok := d.GetOk(prefix + path)
if !ok {
continue
}
}

renameAlias(dto, from, to)
}

// Converts ip_filter list into an expected by the config type
return convertIPFilter(dto)
}

// ipFilterMistyped reverse types: string to map, map to string
// Unmarshalled with no errors when ip_filter has type missmatch
type ipFilterMistyped struct {
IPFilter []map[string]string `json:"ip_filter"`
IPFilterString []map[string]string `json:"ip_filter_string"`
IPFilterObject []string `json:"ip_filter_object"`
}

// convertIPFilter converts a list of ip_filter objects into a list of strings and vice versa
func convertIPFilter(dto map[string]any) error {
b, err := json.Marshal(dto)
if err != nil {
return err
}

var r ipFilterMistyped
err = json.Unmarshal(b, &r)
if err != nil {
// nolint: nilerr
// Marshaling went wrong, nothing to fix
return nil
}

// Converting went smooth.
// Which means either there is no ip_filter at all, or it has an invalid type

// Converts strings into objects
if len(r.IPFilterObject) > 0 {
mapList := make([]map[string]string, 0)
for _, v := range r.IPFilterObject {
mapList = append(mapList, map[string]string{"network": v})
}

dto["ip_filter_object"] = mapList
return nil
}

// Converts objects into strings
strList := make([]string, 0)
for _, v := range append(r.IPFilter, r.IPFilterString...) {
strList = append(strList, v["network"])
}

if len(strList) == 0 {
// Nothing to do here
return nil
}

// Chooses which key to set values to
strKey := "ip_filter"
if len(r.IPFilterString) > 0 {
strKey = "ip_filter_string"
}

dto[strKey] = strList
return nil
}

// renameAlias renames ip_filter_string to ip_filter
Expand Down
58 changes: 57 additions & 1 deletion internal/sdkprovider/userconfig/converters/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,60 @@ func TestRenameAliasesToTfo(t *testing.T) {
dto: `{"pg": {"pg_stat_statements.track": 0}}`,
tfo: newResourceDataMock(),
},
{
serviceType: "thanos",
name: "ip_filter gets a list of objects",
expected: `{"ip_filter": ["0.0.0.0/0"]}`,
dto: `{"ip_filter": [{"network": "0.0.0.0/0"}]}`,
tfo: newResourceDataMock(
newResourceDataKV("thanos_user_config.0.ip_filter", []string{"0.0.0.0/0"}),
),
},
{
serviceType: "thanos",
name: "ip_filter_string gets a list of objects",
expected: `{"ip_filter_string": ["0.0.0.0/0"]}`,
dto: `{"ip_filter": [{"network": "0.0.0.0/0"}]}`,
tfo: newResourceDataMock(
newResourceDataKV("thanos_user_config.0.ip_filter_string", []string{"0.0.0.0/0"}),
),
},
{
serviceType: "thanos",
name: "ip_filter_object gets a list of strings",
expected: `{"ip_filter_object": [{"network": "0.0.0.0/0"}]}`,
dto: `{"ip_filter": ["0.0.0.0/0"]}`,
tfo: newResourceDataMock(
newResourceDataKV("thanos_user_config.0.ip_filter_object", []map[string]string{{"network": "0.0.0.0/0"}}),
),
},
{
serviceType: "thanos",
name: "ip_filter_object empty list",
expected: `{"ip_filter_object": []}`,
dto: `{"ip_filter": []}`,
tfo: newResourceDataMock(
newResourceDataKV("thanos_user_config.0.ip_filter_object", []map[string]string{}),
),
},
{
serviceType: "thanos",
name: "ip_filter_string empty list",
expected: `{"ip_filter_string": []}`,
dto: `{"ip_filter": []}`,
tfo: newResourceDataMock(
newResourceDataKV("thanos_user_config.0.ip_filter_string", []string{}),
),
},
{
serviceType: "thanos",
name: "ip_filter empty list",
expected: `{"ip_filter": []}`,
dto: `{"ip_filter": []}`,
tfo: newResourceDataMock(
newResourceDataKV("thanos_user_config.0.ip_filter", []string{}),
),
},
}

reSpaces := regexp.MustCompile(`\s+`)
Expand All @@ -181,7 +235,9 @@ func TestRenameAliasesToTfo(t *testing.T) {
err := json.Unmarshal([]byte(opt.dto), &m)
require.NoError(t, err)

renameAliasesToTfo(ServiceUserConfig, opt.serviceType, m, opt.tfo)
err = renameAliasesToTfo(ServiceUserConfig, opt.serviceType, m, opt.tfo)
require.NoError(t, err)

b, err := json.Marshal(&m)
require.NoError(t, err)
assert.Equal(t, reSpaces.ReplaceAllString(opt.expected, ""), string(b))
Expand Down

0 comments on commit bf29ca8

Please sign in to comment.