Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support Reconciliation Tracing #8143

Merged
merged 132 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
edcd798
api scaffold
free6om Sep 10, 2024
c355207
embed changes into object tree
free6om Sep 11, 2024
d57e381
workflow style WIP
free6om Sep 11, 2024
0e67c96
workflow style done
free6om Sep 12, 2024
ee8f5ce
make manifests
free6om Sep 12, 2024
de61b49
gpt suggests that
free6om Sep 12, 2024
5ceeb23
make generate
free6om Sep 12, 2024
294cd9d
fix CRD validation error
free6om Sep 12, 2024
b37bc81
view controller WIP
free6om Sep 13, 2024
88cfe52
resources loader, validator done, informer manager WIP
free6om Sep 18, 2024
7d6d2b2
informer manager poc done
free6om Sep 19, 2024
2b8efcf
root finder poc done
free6om Sep 19, 2024
f28798a
view calculation WIP
free6om Sep 19, 2024
b25d5de
view calculation done
free6om Sep 20, 2024
0a8c3ae
view state evaluation WIP
free6om Sep 20, 2024
188bbdb
view state evaluation done
free6om Sep 23, 2024
91dc8d5
object store done
free6om Sep 23, 2024
fe89ded
debug view controller
free6om Sep 23, 2024
6b848e2
debug view controller
free6om Sep 23, 2024
f791e64
viewResourses() works
free6om Sep 23, 2024
f289b55
viewResourcesValidation() works
free6om Sep 23, 2024
202e83b
updateInformerManager() works
free6om Sep 23, 2024
22cfaa5
viewCalculation() works
free6om Sep 23, 2024
fb576e3
viewStateEvaluation() works
free6om Sep 23, 2024
0c164b3
view.status update works
free6om Sep 24, 2024
a878f48
fix infinite view.status update
free6om Sep 24, 2024
16908d3
handle store lost after controller restarted
free6om Sep 24, 2024
cd08fc0
code cleanup
free6om Sep 24, 2024
9077b09
add observed generation fields
free6om Sep 24, 2024
ee1a0c0
plan controller, planResources(), planResourcesValidation() done, pla…
free6om Sep 24, 2024
bd8ea76
planGeneration() WIP
free6om Sep 24, 2024
6f0f792
planGeneration() done
free6om Sep 25, 2024
ee52232
plan controller works
free6om Sep 25, 2024
4be0e01
code cleanup, kbagent dry-run mode
free6om Sep 25, 2024
fb01638
remove ReconciliationViewDefinition
free6om Sep 25, 2024
75ab43f
merge ReconciliationPlan into ReconciliationView
free6om Sep 26, 2024
a0f689e
complete Cluster rules
free6om Sep 26, 2024
e48b8fd
mock reconciler WIP
free6om Sep 26, 2024
398ca44
mock reconciler done
free6om Sep 27, 2024
145ed26
refine store
free6om Sep 27, 2024
8f75f86
Merge branch 'main' into support/reconciliation-view
free6om Sep 27, 2024
c7cf952
bump KB API to v1
free6om Sep 27, 2024
8c024e9
fix kustmization.yaml
free6om Sep 27, 2024
954150e
bugfix
free6om Sep 27, 2024
3ff9195
code cleanup
free6om Sep 28, 2024
64ccd16
ownership validation, code cleanup
free6om Sep 28, 2024
12aa1c0
fix ownership validation
free6om Sep 28, 2024
d2e6db9
fix Configuration apiVersion, run plan generation with timeout
free6om Sep 29, 2024
9552951
adjust structure of DryRunResult
free6om Sep 29, 2024
987b2e6
set Depth default to 0
free6om Sep 29, 2024
a9832cc
i18n resources manager
free6om Sep 29, 2024
66e0f64
handle event WIP
free6om Sep 29, 2024
6411aba
handle event done
free6om Sep 29, 2024
dd563cc
get involved object of event
free6om Sep 29, 2024
5c2efaa
add some todos
free6om Sep 29, 2024
3d84e4c
re-org code
free6om Sep 30, 2024
d1d7aa3
fix staticcheck & golint error
free6om Sep 30, 2024
73c88af
handle deletion done
free6om Sep 30, 2024
e8fc6a6
fix missing arg
free6om Sep 30, 2024
ca059ed
Merge branch 'main' into support/reconciliation-view
free6om Oct 8, 2024
6ee26af
fix sort error
free6om Oct 8, 2024
dd92b20
fix NPE
free6om Oct 8, 2024
913896e
event cleanup, findMatchedRules()
free6om Oct 8, 2024
c76b082
Merge branch 'main' into support/reconciliation-view
free6om Oct 8, 2024
83b9bb7
relax chinese check
free6om Oct 8, 2024
4eb6a97
remove leagcy import
free6om Oct 8, 2024
a468b07
relax chinese check
free6om Oct 8, 2024
04e3030
ut util_test WIP
free6om Oct 8, 2024
2a9e9f7
try fix ci error
free6om Oct 14, 2024
8903863
try fix ci error
free6om Oct 14, 2024
fca2d27
init scheme
free6om Oct 14, 2024
2a7c870
try fix ci error
free6om Oct 14, 2024
60b47f8
Revert "try fix ci error"
free6om Oct 14, 2024
ca20ea9
ut for getObjectReference
free6om Oct 14, 2024
08a41a3
try fix ci error
free6om Oct 14, 2024
644e71e
try fix ci error
free6om Oct 14, 2024
615b485
try fix ci error
free6om Oct 14, 2024
af8b8a5
try fix ci error
free6om Oct 14, 2024
6ffa1b9
Revert "try fix ci error"
free6om Oct 14, 2024
6abdcd4
ut WIP
free6om Oct 14, 2024
6618b21
test view only
free6om Oct 14, 2024
3ab1ac1
verbose
free6om Oct 14, 2024
d1d45ed
verbose
free6om Oct 14, 2024
0dffb36
verbose3
free6om Oct 14, 2024
13df22f
verbose4
free6om Oct 14, 2024
eade629
fix lint error
free6om Oct 14, 2024
885a7af
revert verbose
free6om Oct 14, 2024
fbb18e9
useTestEnvCfg
free6om Oct 14, 2024
a342017
ci error fixed
free6om Oct 14, 2024
144bc85
util ut WIP
free6om Oct 14, 2024
7628fb4
rename view to trace
free6om Oct 15, 2024
044ea98
Merge branch 'main' into support/reconciliation-view
free6om Oct 15, 2024
81c7c3e
util ut done
free6om Oct 16, 2024
93db999
fix lint error
free6om Oct 16, 2024
7d948ee
change_capture_store ut done
free6om Oct 16, 2024
e12e437
object_revision_store ut done
free6om Oct 17, 2024
6e13875
reconciler_tree ut done
free6om Oct 17, 2024
6b44def
fix scheme error
free6om Oct 17, 2024
c895201
current_state_handler ut done
free6om Oct 17, 2024
c2516a7
deletion_handler ut done
free6om Oct 17, 2024
6621d11
desired_state_handler ut WIP
free6om Oct 17, 2024
8661897
desired_state_handler ut WIP
free6om Oct 18, 2024
8f7d74c
desired_state_handler ut WIP
free6om Oct 18, 2024
07b35bd
desired_state_handler ut done
free6om Oct 20, 2024
430e447
desired_state_handler ut done
free6om Oct 20, 2024
105809f
fix broken ut, fix lint error
free6om Oct 20, 2024
2b85675
count changes without event
free6om Oct 21, 2024
d2261df
dry_run_handler ut done
free6om Oct 21, 2024
dc64642
finalizer_handler ut done
free6om Oct 21, 2024
6e2f344
deletion_handler ut for pre-condition
free6om Oct 21, 2024
a515a58
dry_run_handler ut for pre-condition
free6om Oct 21, 2024
e482166
resources loader, validator ut done
free6om Oct 21, 2024
ce09dc3
object_tree_root_finder ut done
free6om Oct 21, 2024
0dadc9c
fix k8sMock related issue
free6om Oct 21, 2024
c138c43
fix panic error
free6om Oct 21, 2024
d511335
fix event loss issue
free6om Oct 22, 2024
9f4f798
fix deletion issue
free6om Oct 22, 2024
c8c2ec7
fix panic on trace creation
free6om Oct 22, 2024
87e4684
remove Depth
free6om Oct 29, 2024
734d317
Merge branch 'main' into support/reconciliation-view
free6om Nov 22, 2024
79de046
refine based on review comments
free6om Nov 22, 2024
626ee7a
refine based on review comments
free6om Nov 22, 2024
5260710
refine based on review comments
free6om Nov 22, 2024
2557e0a
refine based on review comments
free6om Nov 22, 2024
9695815
refine based on review comments
free6om Nov 22, 2024
09bb3c6
refine based on review comments
free6om Nov 22, 2024
eb1e5e5
refine based on review comments
free6om Nov 23, 2024
3578ce1
return a copy
free6om Nov 23, 2024
71735bc
set latestReconciliationCycleStart default to -1
free6om Nov 25, 2024
0ee3972
using logger instead of fmt.Printf
free6om Nov 25, 2024
ac2a73c
disable Trace by default
free6om Nov 25, 2024
5d8a50e
new instance by reflect
free6om Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 27 additions & 27 deletions apis/trace/v1/reconciliationtrace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,35 +149,35 @@ type DryRunResult struct {
// SpecDiff describes the diff between the current spec and the final spec.
// The whole spec struct will be compared and an example SpecDiff looks like:
// {
// Affinity: {
// PodAntiAffinity: "Preferred",
// Tenancy: "SharedNode",
// },
// Affinity: {
// PodAntiAffinity: "Preferred",
// Tenancy: "SharedNode",
// },
// ComponentSpecs: {
free6om marked this conversation as resolved.
Show resolved Hide resolved
// {
// {
// ComponentDef: "postgresql",
// Name: "postgresql",
// - Replicas: 2,
// + Replicas: 3,
// Resources:
// {
// Limits:
// {
// - CPU: 500m,
// + CPU: 800m,
// - Memory: 512Mi,
// + Memory: 768Mi,
// },
// Requests:
// {
// - CPU: 500m,
// + CPU: 800m,
// - Memory: 512Mi,
// + Memory: 768Mi,
// },
// },
// },
// },
// Name: "postgresql",
// - Replicas: 2,
// + Replicas: 3,
// Resources:
// {
// Limits:
// {
// - CPU: 500m,
// + CPU: 800m,
// - Memory: 512Mi,
// + Memory: 768Mi,
// },
// Requests:
// {
// - CPU: 500m,
// + CPU: 800m,
// - Memory: 512Mi,
// + Memory: 768Mi,
// },
// },
// },
// },
// }
//
SpecDiff string `json:"specDiff"`
Expand Down
2 changes: 1 addition & 1 deletion apis/workloads/v1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ var (
AddToScheme = SchemeBuilder.AddToScheme
)

const Kind = "InstanceSet"
const InstanceSetKind = "InstanceSet"
2 changes: 1 addition & 1 deletion cmd/dataprotection/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func main() {
if len(managedNamespaces) > 0 {
setupLog.Info(fmt.Sprintf("managed namespaces: %s", managedNamespaces))
}
mgr, err := ctrl.NewManager(intctrlutil.GeKubeRestConfig(userAgent), ctrl.Options{
mgr, err := ctrl.NewManager(intctrlutil.GetKubeRestConfig(userAgent), ctrl.Options{
Scheme: scheme,
Metrics: server.Options{
BindAddress: metricsAddr,
Expand Down
2 changes: 1 addition & 1 deletion cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ func main() {
userAgent = viper.GetString(userAgentFlagKey.viperName())

setupLog.Info("golang runtime metrics.", "featureGate", intctrlutil.EnabledRuntimeMetrics())
mgr, err := ctrl.NewManager(intctrlutil.GeKubeRestConfig(userAgent), ctrl.Options{
mgr, err := ctrl.NewManager(intctrlutil.GetKubeRestConfig(userAgent), ctrl.Options{
Scheme: scheme,
Metrics: server.Options{
BindAddress: metricsAddr,
Expand Down
15 changes: 8 additions & 7 deletions config/crd/bases/trace.kubeblocks.io_reconciliationtraces.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -865,13 +865,14 @@ spec:
specDiff:
description: "SpecDiff describes the diff between the current
spec and the final spec.\nThe whole spec struct will be compared
and an example SpecDiff looks like:\n{\n\t\tAffinity: {\n \t\tPodAntiAffinity:
\"Preferred\",\n \t\tTenancy: \"SharedNode\",\n\t\t},\n \tComponentSpecs:
{\n\t\t\t{\n \t\t\tComponentDef: \"postgresql\",\n \t\t\tName:
\"postgresql\",\n- \t\tReplicas: 2,\n \t\t\tResources:\n\t\t\t\t{\n
\ \t\t\tLimits:\n\t\t\t\t\t{\n- \t\t\tCPU: 500m,\n-
\ \t\t\t\tMemory: 512Mi,\n\t\t\t\t\t},\n \t\t\tRequests:\n\t\t\t\t\t{\n-
\ \t\t\t\tCPU: 500m,\n- \t\t\t\tMemory: 512Mi,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n}"
and an example SpecDiff looks like:\n{\n \tAffinity: {\n \t\tPodAntiAffinity:
\"Preferred\",\n \t\tTenancy: \"SharedNode\",\n \t},\n \tComponentSpecs:
{\n \t\t{\n \t\t\tComponentDef: \"postgresql\",\n \t\t\tName:
\"postgresql\",\n-\t\t\tReplicas: 2,\n \t\t\tResources:\n \t\t\t{\n
\t\t\t\tLimits:\n \t\t\t\t{\n-\t\t\t\t\tCPU: 500m,\n-\t\t\t\t\tMemory:
512Mi,\n \t\t\t\t},\n \t\t\t\tRequests:\n \t\t\t\t{\n-\t\t\t\t\tCPU:
500m,\n-\t\t\t\t\tMemory: 512Mi,\n \t\t\t\t},\n \t\t\t},\n \t\t},\n
\t},\n}"
type: string
required:
- desiredSpecRevision
Expand Down
2 changes: 1 addition & 1 deletion controllers/apps/component_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ var _ = Describe("Component Utils", func() {
)
pod := testapps.MockInstanceSetPod(&testCtx, nil, clusterName, compName, podName, role, mode)
ppod := testapps.NewPodFactory(testCtx.DefaultNamespace, "pod").
SetOwnerReferences(workloads.GroupVersion.String(), workloads.Kind, nil).
SetOwnerReferences(workloads.GroupVersion.String(), workloads.InstanceSetKind, nil).
AddAppInstanceLabel(clusterName).
AddAppComponentLabel(compName).
AddAppManagedByLabel().
Expand Down
4 changes: 2 additions & 2 deletions controllers/apps/configuration/policy_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ import (

var (
defaultNamespace = "default"
itsSchemaKind = workloads.GroupVersion.WithKind(workloads.Kind)
itsSchemaKind = workloads.GroupVersion.WithKind(workloads.InstanceSetKind)
)

func newMockInstanceSet(replicas int, name string, labels map[string]string) workloads.InstanceSet {
uid, _ := password.Generate(12, 12, 0, true, false)
return workloads.InstanceSet{
TypeMeta: metav1.TypeMeta{
Kind: workloads.Kind,
Kind: workloads.InstanceSetKind,
APIVersion: workloads.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Expand Down
2 changes: 1 addition & 1 deletion controllers/apps/transform_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func isOwnedByComp(obj client.Object) bool {
// isOwnedByInstanceSet is used to judge if the obj is owned by the InstanceSet controller
func isOwnedByInstanceSet(obj client.Object) bool {
for _, ref := range obj.GetOwnerReferences() {
if ref.Kind == workloads.Kind && ref.Controller != nil && *ref.Controller {
if ref.Kind == workloads.InstanceSetKind && ref.Controller != nil && *ref.Controller {
return true
}
}
Expand Down
2 changes: 1 addition & 1 deletion controllers/apps/transform_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func TestIsOwnedByInstanceSet(t *testing.T) {

its.OwnerReferences = []metav1.OwnerReference{
{
Kind: workloads.Kind,
Kind: workloads.InstanceSetKind,
Controller: pointer.Bool(true),
},
}
Expand Down
4 changes: 2 additions & 2 deletions controllers/apps/transformer_component_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func (t *componentStatusTransformer) hasFailedPod() (bool, appsv1alpha1.Componen
hasFailedPod := meta.IsStatusConditionTrue(t.runningITS.Status.Conditions, string(workloads.InstanceFailure))
if hasFailedPod {
failureCondition := meta.FindStatusCondition(t.runningITS.Status.Conditions, string(workloads.InstanceFailure))
messages.SetObjectMessage(workloads.Kind, t.runningITS.Name, failureCondition.Message)
messages.SetObjectMessage(workloads.InstanceSetKind, t.runningITS.Name, failureCondition.Message)
return true, messages
}

Expand All @@ -309,7 +309,7 @@ func (t *componentStatusTransformer) hasFailedPod() (bool, appsv1alpha1.Componen
probeTimeoutDuration := time.Duration(defaultRoleProbeTimeoutAfterPodsReady) * time.Second
condition := meta.FindStatusCondition(t.runningITS.Status.Conditions, string(workloads.InstanceReady))
if time.Now().After(condition.LastTransitionTime.Add(probeTimeoutDuration)) {
messages.SetObjectMessage(workloads.Kind, t.runningITS.Name, "Role probe timeout, check whether the application is available")
messages.SetObjectMessage(workloads.InstanceSetKind, t.runningITS.Name, "Role probe timeout, check whether the application is available")
return true, messages
}

Expand Down
10 changes: 5 additions & 5 deletions controllers/trace/change_capture_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ package trace
import (
"sort"
"strconv"
"sync/atomic"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand All @@ -47,16 +46,16 @@ type changeCaptureStore struct {
scheme *runtime.Scheme
formatter descriptionFormatter
store map[model.GVKNObjKey]client.Object
zjx20 marked this conversation as resolved.
Show resolved Hide resolved
clock atomic.Int64
clock int64
changes []tracev1.ObjectChange
}

func (s *changeCaptureStore) Load(objects ...client.Object) error {
for _, object := range objects {
// sync the clock
revision := parseRevision(object.GetResourceVersion())
if revision > s.clock.Load() {
s.clock.Store(revision)
if revision > s.clock {
s.clock = revision
}
objectRef, err := getObjectRef(object, s.scheme)
if err != nil {
Expand Down Expand Up @@ -161,7 +160,8 @@ func newChangeCaptureStore(scheme *runtime.Scheme, formatter descriptionFormatte
}

func (s *changeCaptureStore) applyRevision() string {
return strconv.FormatInt(s.clock.Add(1), 10)
s.clock++
return strconv.FormatInt(s.clock, 10)
}

func (s *changeCaptureStore) captureCreation(objectRef *model.GVKNObjKey, object client.Object) {
Expand Down
5 changes: 5 additions & 0 deletions controllers/trace/desired_state_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ var _ = Describe("desired_state_handler test", func() {
list.Items = []kbappsv1.ComponentVersion{*componentVersion.DeepCopy()}
return nil
}).AnyTimes()
k8sMock.EXPECT().
List(gomock.Any(), &kbappsv1.SidecarDefinitionList{}, gomock.Any()).
DoAndReturn(func(_ context.Context, list *kbappsv1.SidecarDefinitionList, _ ...client.ListOption) error {
return nil
}).AnyTimes()
k8sMock.EXPECT().
List(gomock.Any(), &dpv1alpha1.BackupPolicyTemplateList{}, gomock.Any()).
DoAndReturn(func(_ context.Context, list *dpv1alpha1.BackupPolicyTemplateList, _ ...client.ListOption) error {
Expand Down
5 changes: 5 additions & 0 deletions controllers/trace/dry_run_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ var _ = Describe("dry_run_handler test", func() {
list.Items = []kbappsv1.ComponentVersion{*componentVersion.DeepCopy()}
return nil
}).AnyTimes()
k8sMock.EXPECT().
List(gomock.Any(), &kbappsv1.SidecarDefinitionList{}, gomock.Any()).
DoAndReturn(func(_ context.Context, list *kbappsv1.SidecarDefinitionList, _ ...client.ListOption) error {
return nil
}).AnyTimes()
k8sMock.EXPECT().
List(gomock.Any(), &dpv1alpha1.BackupPolicyTemplateList{}, gomock.Any()).
DoAndReturn(func(_ context.Context, list *dpv1alpha1.BackupPolicyTemplateList, _ ...client.ListOption) error {
Expand Down
3 changes: 2 additions & 1 deletion controllers/trace/informer_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ func (m *informerManager) processNextWorkItem() bool {
if evt, ok := object.(*corev1.Event); ok {
ro, err := m.scheme.New(evt.InvolvedObject.GroupVersionKind())
if err != nil {
return false
m.logger.Error(err, "new an event involved object failed")
return true
}
object, _ = ro.(client.Object)
err = m.cli.Get(context.Background(), client.ObjectKey{Namespace: evt.InvolvedObject.Namespace, Name: evt.InvolvedObject.Name}, object)
Expand Down
39 changes: 30 additions & 9 deletions controllers/trace/mock_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ func (c *mockClient) Delete(ctx context.Context, obj client.Object, opts ...clie
object.SetDeletionTimestamp(&ts)
return c.store.Update(object)
}
if len(object.GetFinalizers()) != 0 {
return nil
}
return c.store.Delete(obj)
free6om marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -175,8 +178,8 @@ func doPatch(obj client.Object, patch client.Patch, store ChangeCaptureStore, sc
if err != nil {
return err
}
newObj := oldObj.DeepCopyObject().(client.Object)
if err = applyPatch(newObj, patch.Type(), patchData); err != nil {
newObj, err := applyPatch(oldObj, patch.Type(), patchData)
if err != nil {
return err
}
metaChanged := checkMetadata(oldObj, newObj)
Expand All @@ -193,11 +196,11 @@ func doPatch(obj client.Object, patch client.Patch, store ChangeCaptureStore, sc
return nil
}

func applyPatch(obj client.Object, patchType types.PatchType, patchData []byte) error {
func applyPatch(obj client.Object, patchType types.PatchType, patchData []byte) (client.Object, error) {
// Convert the object to JSON
originalJSON, err := json.Marshal(obj)
if err != nil {
return fmt.Errorf("failed to marshal original object: %w", err)
return nil, fmt.Errorf("failed to marshal original object: %w", err)
}

// Apply the patch
Expand All @@ -208,14 +211,32 @@ func applyPatch(obj client.Object, patchType types.PatchType, patchData []byte)
case types.MergePatchType:
patchedJSON, err = jsonpatch.MergePatch(originalJSON, patchData)
default:
return fmt.Errorf("unsupported patch type: %s", patchType)
return nil, fmt.Errorf("unsupported patch type: %s", patchType)
}
if err != nil {
return fmt.Errorf("failed to apply patch: %w", err)
return nil, fmt.Errorf("failed to apply patch: %w", err)
}

// Unmarshal the patched JSON back into the object
return json.Unmarshal(patchedJSON, obj)
// Unmarshal the patched JSON into a new clean object
newObj := obj.DeepCopyObject().(client.Object)
free6om marked this conversation as resolved.
Show resolved Hide resolved
zeroOutStruct(newObj)
err = json.Unmarshal(patchedJSON, newObj)
return newObj, err
}

// zeroOutStruct zero out a struct
func zeroOutStruct(i interface{}) {
v := reflect.ValueOf(i)
if v.Kind() != reflect.Ptr {
return // Must be a pointer
}
elem := v.Elem()
if elem.Kind() != reflect.Struct {
return // Must be pointing to a struct
}
// Create zero value of the same type and set it
zero := reflect.Zero(elem.Type())
elem.Set(zero)
}

func checkMetadata(oldObj client.Object, newObj client.Object) bool {
Expand Down Expand Up @@ -257,7 +278,7 @@ func checkStatus(oldObj client.Object, newObj client.Object) bool {
}

func (c *mockClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
panic("not implemented")
return fmt.Errorf("DeleteAllOf not implemented")
}

func (c *mockClient) Status() client.SubResourceWriter {
Expand Down
20 changes: 17 additions & 3 deletions controllers/trace/object_revision_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ import (
"github.com/apecloud/kubeblocks/pkg/controller/model"
)

// ObjectRevisionStore defines an object store which can get the history revision.
// WARN: This store is designed only for Reconciliation Trace Controller,
// it's not thread-safe, it doesn't do a deep copy before returning the object.
// Don't use it in other place.
type ObjectRevisionStore interface {
Insert(object, reference client.Object) error
Get(objectRef *model.GVKNObjKey, revision int64) (client.Object, error)
Expand Down Expand Up @@ -67,15 +71,15 @@ func (s *objectRevisionStore) Insert(object, reference client.Object) error {
objectMap, ok := s.store[objectRef.GroupVersionKind]
if !ok {
objectMap = make(map[types.NamespacedName]map[int64]client.Object)
s.store[objectRef.GroupVersionKind] = objectMap
}
revisionMap, ok := objectMap[objectRef.ObjectKey]
if !ok {
revisionMap = make(map[int64]client.Object)
objectMap[objectRef.ObjectKey] = revisionMap
}
revision := parseRevision(object.GetResourceVersion())
revisionMap[revision] = object
objectMap[objectRef.ObjectKey] = revisionMap
s.store[objectRef.GroupVersionKind] = objectMap

// update reference counter
s.counterLock.Lock()
Expand Down Expand Up @@ -111,6 +115,7 @@ func (s *objectRevisionStore) Get(objectRef *model.GVKNObjKey, revision int64) (
if !ok {
return nil, apierrors.NewNotFound(objectRef.GroupVersion().WithResource(strings.ToLower(objectRef.Kind)).GroupResource(), objectRef.Name)
}
object = object.DeepCopyObject().(client.Object)
return object, nil
}

Expand All @@ -122,7 +127,16 @@ func (s *objectRevisionStore) List(gvk *schema.GroupVersionKind) map[types.Names
if !ok {
return nil
}
return objectMap
objectMapCopy := make(map[types.NamespacedName]map[int64]client.Object, len(objectMap))
for name, revisionMap := range objectMap {
revisionMapCopy := make(map[int64]client.Object, len(revisionMap))
objectMapCopy[name] = revisionMapCopy
for revision, object := range revisionMap {
objectCopy := object.DeepCopyObject().(client.Object)
revisionMapCopy[revision] = objectCopy
}
}
return objectMapCopy
}

func (s *objectRevisionStore) Delete(objectRef *model.GVKNObjKey, reference client.Object, revision int64) {
Expand Down
Loading
Loading