From 6832900c8073e0f4ab996cf198de3ae3cccc4c0d Mon Sep 17 00:00:00 2001 From: Rory Z <16801068+Rory-Z@users.noreply.github.com> Date: Tue, 9 Jan 2024 17:54:16 +0800 Subject: [PATCH] fix: fix config map always update Signed-off-by: Rory Z <16801068+Rory-Z@users.noreply.github.com> --- controllers/apps/v2beta1/sync_emqx_config.go | 56 +++++-- .../apps/v2beta1/sync_emqx_config_test.go | 148 ++++++++++++++++++ 2 files changed, 191 insertions(+), 13 deletions(-) create mode 100644 controllers/apps/v2beta1/sync_emqx_config_test.go diff --git a/controllers/apps/v2beta1/sync_emqx_config.go b/controllers/apps/v2beta1/sync_emqx_config.go index a76b772d6..719bd30d0 100644 --- a/controllers/apps/v2beta1/sync_emqx_config.go +++ b/controllers/apps/v2beta1/sync_emqx_config.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "reflect" "strings" emperror "emperror.dev/errors" @@ -33,7 +32,7 @@ func (s *syncConfig) reconcile(ctx context.Context, logger logr.Logger, instance } lastHoconConfig, _ := hocon.ParseString(lastConfigStr) - if !reflect.DeepEqual(hoconConfig, lastHoconConfig) { + if !deepEqualHoconValue(hoconConfig.GetRoot(), lastHoconConfig.GetRoot()) { _, coreReady := instance.Status.GetCondition(appsv2beta1.CoreNodesReady) if coreReady == nil || !instance.Status.IsConditionTrue(appsv2beta1.CoreNodesReady) { return subResult{} @@ -76,17 +75,6 @@ func (s *syncConfig) update(ctx context.Context, logger logr.Logger, instance *a return nil } -func mergeDefaultConfig(config string) *hocon.Config { - defaultListenerConfig := "" - defaultListenerConfig += fmt.Sprintln("listeners.tcp.default.bind = 1883") - defaultListenerConfig += fmt.Sprintln("listeners.ssl.default.bind = 8883") - defaultListenerConfig += fmt.Sprintln("listeners.ws.default.bind = 8083") - defaultListenerConfig += fmt.Sprintln("listeners.wss.default.bind = 8084") - - hoconConfig, _ := hocon.ParseString(defaultListenerConfig + config) - return hoconConfig -} - func generateConfigMap(instance *appsv2beta1.EMQX, data string) *corev1.ConfigMap { return &corev1.ConfigMap{ TypeMeta: metav1.TypeMeta{ @@ -118,3 +106,45 @@ func putEMQXConfigsByAPI(r innerReq.RequesterInterface, mode, config string) err } return nil } + +func mergeDefaultConfig(config string) *hocon.Config { + defaultListenerConfig := "" + defaultListenerConfig += fmt.Sprintln("listeners.tcp.default.bind = 1883") + defaultListenerConfig += fmt.Sprintln("listeners.ssl.default.bind = 8883") + defaultListenerConfig += fmt.Sprintln("listeners.ws.default.bind = 8083") + defaultListenerConfig += fmt.Sprintln("listeners.wss.default.bind = 8084") + + hoconConfig, _ := hocon.ParseString(defaultListenerConfig + config) + return hoconConfig +} + +func deepEqualHoconValue(val1, val2 hocon.Value) bool { + switch val1.Type() { + case hocon.ObjectType: + if len(val1.(hocon.Object)) != len(val2.(hocon.Object)) { + return false + } + for key := range val1.(hocon.Object) { + if _, ok := val2.(hocon.Object)[key]; !ok { + return false + } + if !deepEqualHoconValue(val1.(hocon.Object)[key], val2.(hocon.Object)[key]) { + return false + } + } + case hocon.ArrayType: + if len(val1.(hocon.Array)) != len(val2.(hocon.Array)) { + return false + } + for i := range val1.(hocon.Array) { + if !deepEqualHoconValue(val1.(hocon.Array)[i], val2.(hocon.Array)[i]) { + return false + } + } + case hocon.StringType, hocon.NumberType, hocon.BooleanType, hocon.NullType: + return val1.String() == val2.String() + default: + return false + } + return true +} diff --git a/controllers/apps/v2beta1/sync_emqx_config_test.go b/controllers/apps/v2beta1/sync_emqx_config_test.go new file mode 100644 index 000000000..2837ac7a8 --- /dev/null +++ b/controllers/apps/v2beta1/sync_emqx_config_test.go @@ -0,0 +1,148 @@ +package v2beta1 + +import ( + "fmt" + "testing" + + "github.com/rory-z/go-hocon" + "github.com/stretchr/testify/assert" +) + +func TestMergeDefaultConfig(t *testing.T) { + t.Run("case1", func(t *testing.T) { + config := "" + got := mergeDefaultConfig(config) + assert.Equal(t, "1883", got.GetString("listeners.tcp.default.bind")) + assert.Equal(t, "8883", got.GetString("listeners.ssl.default.bind")) + assert.Equal(t, "8083", got.GetString("listeners.ws.default.bind")) + assert.Equal(t, "8084", got.GetString("listeners.wss.default.bind")) + }) + + t.Run("case2", func(t *testing.T) { + config := "" + config += fmt.Sprintln("listeners.tcp.default.bind = 31883") + config += fmt.Sprintln("listeners.ssl.default.bind = 38883") + config += fmt.Sprintln("listeners.ws.default.bind = 38083") + config += fmt.Sprintln("listeners.wss.default.bind = 38084") + + got := mergeDefaultConfig(config) + assert.Equal(t, "31883", got.GetString("listeners.tcp.default.bind")) + assert.Equal(t, "38883", got.GetString("listeners.ssl.default.bind")) + assert.Equal(t, "38083", got.GetString("listeners.ws.default.bind")) + assert.Equal(t, "38084", got.GetString("listeners.wss.default.bind")) + }) +} + +func TestDeepEqualHoconValue(t *testing.T) { + t.Run("case1", func(t *testing.T) { + v1 := hocon.String("a") + v2 := hocon.String("a") + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case2", func(t *testing.T) { + v1 := hocon.String("a") + v2 := hocon.String("b") + assert.False(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case3", func(t *testing.T) { + v1 := hocon.Int(1) + v2 := hocon.Int(1) + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case4", func(t *testing.T) { + v1 := hocon.Int(1) + v2 := hocon.Int(2) + assert.False(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case5", func(t *testing.T) { + v1 := hocon.Boolean(true) + v2 := hocon.Boolean(true) + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case6", func(t *testing.T) { + v1 := hocon.Boolean(true) + v2 := hocon.Boolean(false) + assert.False(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case7", func(t *testing.T) { + v1 := hocon.Null("null") + v2 := hocon.Null("null") + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case8", func(t *testing.T) { + v1 := hocon.Null("fake") + v2 := hocon.Null("") + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case9", func(t *testing.T) { + v1 := hocon.Array{hocon.String("a"), hocon.String("b")} + v2 := hocon.Array{hocon.String("a"), hocon.String("b")} + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case10", func(t *testing.T) { + v1 := hocon.Array{hocon.String("a"), hocon.String("b")} + v2 := hocon.Array{hocon.String("a"), hocon.String("c")} + assert.False(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case11", func(t *testing.T) { + v1 := hocon.Array{hocon.String("a"), hocon.String("b")} + v2 := hocon.Array{hocon.String("a"), hocon.String("b"), hocon.String("c")} + assert.False(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case12", func(t *testing.T) { + v1 := hocon.Object{"a": hocon.Int(1), "b": hocon.Int(2)} + v2 := hocon.Object{"b": hocon.Int(2), "a": hocon.Int(1)} + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case13", func(t *testing.T) { + v1 := hocon.Object{"a": hocon.Int(1), "b": hocon.Int(2)} + v2 := hocon.Object{"a": hocon.Int(1), "c": hocon.Int(3)} + assert.False(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case13", func(t *testing.T) { + v1 := hocon.Object{"a": hocon.Int(1), "b": hocon.Int(2)} + v2 := hocon.Object{"a": hocon.Int(1), "b": hocon.Int(2), "c": hocon.Int(3)} + assert.False(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case14", func(t *testing.T) { + v1 := hocon.Object{ + "a": hocon.String("a1"), + "b": hocon.Object{"b1": hocon.String("b1"), "b2": hocon.String("b2")}, + "c": hocon.Array{hocon.String("c1"), hocon.String("c2")}, + } + v2 := hocon.Object{ + "c": hocon.Array{hocon.String("c1"), hocon.String("c2")}, + "b": hocon.Object{"b2": hocon.String("b2"), "b1": hocon.String("b1")}, + "a": hocon.String("a1"), + } + assert.True(t, deepEqualHoconValue(v1, v2)) + }) + + t.Run("case15", func(t *testing.T) { + v1 := hocon.Object{ + "a": hocon.String("a1"), + "b": hocon.Object{"b1": hocon.String("b1"), "b2": hocon.String("b2")}, + "c": hocon.Array{hocon.String("c1"), hocon.String("c2")}, + } + v2 := hocon.Object{ + "c": hocon.Array{hocon.String("c2"), hocon.String("c1")}, + "b": hocon.Object{"b2": hocon.String("b2"), "b1": hocon.String("b1")}, + "a": hocon.String("a1"), + } + assert.False(t, deepEqualHoconValue(v1, v2)) + }) +}