diff --git a/controllers/sriovnetworknodepolicy_controller.go b/controllers/sriovnetworknodepolicy_controller.go index e913530a5..3ba1e4144 100644 --- a/controllers/sriovnetworknodepolicy_controller.go +++ b/controllers/sriovnetworknodepolicy_controller.go @@ -25,6 +25,8 @@ import ( "strings" "time" + utils "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils" + errs "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -257,7 +259,7 @@ func (r *SriovNetworkNodePolicyReconciler) syncAllSriovNetworkNodeStates(ctx con ns.Namespace = namespace j, _ := json.Marshal(ns) logger.Info("SriovNetworkNodeState CR", "content", j) - if err := r.syncSriovNetworkNodeState(ctx, np, npl, ns, &node, found.GetResourceVersion()); err != nil { + if err := r.syncSriovNetworkNodeState(ctx, np, npl, ns, &node, utils.HashConfigMap(found)); err != nil { logger.Error(err, "Fail to sync", "SriovNetworkNodeState", ns.Name) return err } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 051a4aebb..403d509ac 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -16,6 +16,12 @@ import ( "syscall" "time" + "encoding/hex" + "hash/fnv" + "sort" + + corev1 "k8s.io/api/core/v1" + "github.com/cenkalti/backoff" "github.com/jaypipes/ghw" "github.com/vishvananda/netlink" @@ -921,6 +927,22 @@ func RunCommand(command string, args ...string) (string, error) { return stdout.String(), err } +func HashConfigMap(cm *corev1.ConfigMap) string { + var keys []string + for k := range cm.Data { + keys = append(keys, k) + } + sort.Strings(keys) + + hash := fnv.New128() + for _, k := range keys { + hash.Write([]byte(k)) + hash.Write([]byte(cm.Data[k])) + } + hashed := hash.Sum(nil) + return hex.EncodeToString(hashed) +} + func hasMellanoxInterfacesInSpec(ifaceStatuses sriovnetworkv1.InterfaceExts, ifaceSpecs sriovnetworkv1.Interfaces) bool { for _, ifaceStatus := range ifaceStatuses { if ifaceStatus.Vendor == VendorMellanox { diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go new file mode 100644 index 000000000..0b4feb1a2 --- /dev/null +++ b/pkg/utils/utils_test.go @@ -0,0 +1,77 @@ +package utils_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + utils "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils" +) + +var _ = Describe("HashConfigMap", func() { + It("should hash the ConfigMap correctly", func() { + data := make(map[string]string) + data["key1"] = "value1" + data["key2"] = "value2" + cm := &corev1.ConfigMap{ + Data: data, + } + + expectedHash := "7cb7a94f45100d7dc8aadffbcd409f25" + + actualHash := utils.HashConfigMap(cm) + + Expect(actualHash).To(Equal(expectedHash)) + }) + + It("Should not change hash for different resource versions", func() { + data := make(map[string]string) + data["key1"] = "value1" + data["key2"] = "value2" + + cm1 := &corev1.ConfigMap{ + Data: data, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "68790", + }, + } + + cm2 := &corev1.ConfigMap{ + Data: data, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "69889", + }, + } + + hash1 := utils.HashConfigMap(cm1) + hash2 := utils.HashConfigMap(cm2) + + Expect(hash1).To(Equal(hash2)) + }) + + It("should not change hash for different key orderings", func() { + data1 := map[string]string{} + data1["key1"] = "value1" + data1["key2"] = "value2" + data2 := map[string]string{} + data2["key1"] = "value1" + data2["key2"] = "value2" + // Collisions in the hashmap _can_ change the order of keys + data2["key2"] = "value2" + + cm1 := &corev1.ConfigMap{ + Data: data1, + } + + cm2 := &corev1.ConfigMap{ + Data: data2, + } + + hash1 := utils.HashConfigMap(cm1) + hash2 := utils.HashConfigMap(cm2) + + Expect(hash1).To(Equal(hash2)) + }) +}) diff --git a/pkg/utils/utils_virtual_test.go b/pkg/utils/utils_virtual_test.go index 6890d7304..5c55d4b54 100644 --- a/pkg/utils/utils_virtual_test.go +++ b/pkg/utils/utils_virtual_test.go @@ -12,7 +12,7 @@ import ( "k8s.io/utils/pointer" ) -func TestUtils(t *testing.T) { +func TestUtilsVirtual(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Utils") }