From 0f454e70319f9469b7d2e7dbd9361d071727ff5c Mon Sep 17 00:00:00 2001 From: Kinara Shah Date: Thu, 3 Oct 2024 13:24:14 -0700 Subject: [PATCH] Prevent dropping unknown cluster fields (#515) * Prevents dropping unknown cluster fields Signed-off-by: Dharmit Shah * add test for v3 cluster mutator & add rke to replace in go.mod adding rke to replace section will avoid pulling in rc versions when updating pkg/apis in webhook --- go.mod | 1 + go.sum | 4 +- .../v3/cluster/mutator.go | 9 +++- .../v3/cluster/mutator_test.go | 46 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 pkg/resources/management.cattle.io/v3/cluster/mutator_test.go diff --git a/go.mod b/go.mod index 822c0cc7..a7c68212 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.22.0 toolchain go1.22.7 replace ( + github.com/rancher/rke => github.com/rancher/rke v1.6.2 k8s.io/api => k8s.io/api v0.30.1 k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.30.1 k8s.io/apimachinery => k8s.io/apimachinery v0.30.1 diff --git a/go.sum b/go.sum index b5690e1d..3f3e7899 100644 --- a/go.sum +++ b/go.sum @@ -170,8 +170,8 @@ github.com/rancher/norman v0.0.0-20240822182819-60ccfabc4ac5 h1:Z34NXcW0ymdpVBfd github.com/rancher/norman v0.0.0-20240822182819-60ccfabc4ac5/go.mod h1:dyjfXBsNiroPWOdUZe7diUOUSLf6HQ/r2kEpwH/8zas= github.com/rancher/rancher/pkg/apis v0.0.0-20240903164338-21e4787cd0b3 h1:KCO+g13mukOPpaYFUMmr3oMULltsFbp6H8rp4NV02jI= github.com/rancher/rancher/pkg/apis v0.0.0-20240903164338-21e4787cd0b3/go.mod h1:V1RX7d/ziNUUD0RRz/HDf3xaCZdJPdbXRQLArExtg+U= -github.com/rancher/rke v1.6.0 h1:fHdygmtPF1cWXuiYXfwgG4hKvt0n4l57SwCxquRJSfs= -github.com/rancher/rke v1.6.0/go.mod h1:5xRbf3L8PxqJRhABjYRfaBqbpVqAnqyH3maUNQEuwvk= +github.com/rancher/rke v1.6.2 h1:ttGk77t5oe7bsiS7s7SOFmAl3PALYI5M2SQQenjKevk= +github.com/rancher/rke v1.6.2/go.mod h1:5xRbf3L8PxqJRhABjYRfaBqbpVqAnqyH3maUNQEuwvk= github.com/rancher/wrangler/v3 v3.0.0 h1:IHHCA+vrghJDPxjtLk4fmeSCFhNe9fFzLFj3m2B0YpA= github.com/rancher/wrangler/v3 v3.0.0/go.mod h1:Dfckuuq7MJk2JWVBDywRlZXMxEyPxHy4XqGrPEzu5Eg= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= diff --git a/pkg/resources/management.cattle.io/v3/cluster/mutator.go b/pkg/resources/management.cattle.io/v3/cluster/mutator.go index d93fc985..ad219fae 100644 --- a/pkg/resources/management.cattle.io/v3/cluster/mutator.go +++ b/pkg/resources/management.cattle.io/v3/cluster/mutator.go @@ -1,6 +1,7 @@ package cluster import ( + "encoding/json" "fmt" "reflect" @@ -59,6 +60,10 @@ func (m *ManagementClusterMutator) Admit(request *admission.Request) (*admission if err != nil { return nil, fmt.Errorf("failed to get old and new clusters from request: %w", err) } + newClusterRaw, err := json.Marshal(newCluster) + if err != nil { + return nil, fmt.Errorf("unable to re-marshal new cluster: %w", err) + } // no need to mutate the local cluster, or imported cluster which represents a KEv2 cluster (GKE/EKS/AKS) or v1 Provisioning Cluster if newCluster.Name == "local" || newCluster.Spec.RancherKubernetesEngineConfig == nil { return admission.ResponseAllowed(), nil @@ -94,7 +99,9 @@ func (m *ManagementClusterMutator) Admit(request *admission.Request) (*admission } response := &admissionv1.AdmissionResponse{} - if err := patch.CreatePatch(request.Object.Raw, newCluster, response); err != nil { + // we use the re-marshalled new cluster to make sure that the patch doesn't drop "unknown" fields which were + // in the json, but not in the cluster struct. This can occur due to out of date RKE versions + if err := patch.CreatePatch(newClusterRaw, newCluster, response); err != nil { return response, fmt.Errorf("failed to create patch: %w", err) } response.Allowed = true diff --git a/pkg/resources/management.cattle.io/v3/cluster/mutator_test.go b/pkg/resources/management.cattle.io/v3/cluster/mutator_test.go new file mode 100644 index 00000000..860286c9 --- /dev/null +++ b/pkg/resources/management.cattle.io/v3/cluster/mutator_test.go @@ -0,0 +1,46 @@ +package cluster + +import ( + "encoding/json" + "testing" + + v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" + "github.com/rancher/webhook/pkg/admission" + data2 "github.com/rancher/wrangler/v3/pkg/data" + "github.com/stretchr/testify/assert" + admissionv1 "k8s.io/api/admission/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func TestAdmitPreserveUnknownFields(t *testing.T) { + cluster := &v3.Cluster{} + data, err := data2.Convert(cluster) + assert.Nil(t, err) + + data.SetNested("test", "spec", "rancherKubernetesEngineConfig", "network", "aciNetworkProvider", "apicUserKeyTest") + raw, err := json.Marshal(data) + assert.Nil(t, err) + + request := &admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Object: runtime.RawExtension{ + Raw: raw, + }, + OldObject: runtime.RawExtension{ + Raw: raw, + }, + }, + } + + m := ManagementClusterMutator{} + + request.Operation = admissionv1.Create + response, err := m.Admit(request) + assert.Nil(t, err) + assert.Nil(t, response.Patch) + + request.Operation = admissionv1.Update + response, err = m.Admit(request) + assert.Nil(t, err) + assert.Nil(t, response.Patch) +}