mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
Feat: optimize empty patch request (#5600)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
@@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@@ -121,6 +122,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
|||||||
}
|
}
|
||||||
return r.result(client.IgnoreNotFound(err)).ret()
|
return r.result(client.IgnoreNotFound(err)).ret()
|
||||||
}
|
}
|
||||||
|
ctx = withOriginalApp(ctx, app)
|
||||||
|
|
||||||
if !r.matchControllerRequirement(app) {
|
if !r.matchControllerRequirement(app) {
|
||||||
logCtx.Info("skip app: not match the controller requirement of app")
|
logCtx.Info("skip app: not match the controller requirement of app")
|
||||||
@@ -410,6 +412,9 @@ func (r *Reconciler) endWithNegativeCondition(ctx context.Context, app *v1beta1.
|
|||||||
func (r *Reconciler) patchStatus(ctx context.Context, app *v1beta1.Application, phase common.ApplicationPhase) error {
|
func (r *Reconciler) patchStatus(ctx context.Context, app *v1beta1.Application, phase common.ApplicationPhase) error {
|
||||||
app.Status.Phase = phase
|
app.Status.Phase = phase
|
||||||
updateObservedGeneration(app)
|
updateObservedGeneration(app)
|
||||||
|
if oldApp, ok := originalAppFrom(ctx); ok && oldApp != nil && equality.Semantic.DeepEqual(oldApp.Status, app.Status) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
ctx, cancel := ctrlrec.NewReconcileTerminationContext(ctx)
|
ctx, cancel := ctrlrec.NewReconcileTerminationContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err := r.Status().Patch(ctx, app, client.Merge); err != nil {
|
if err := r.Status().Patch(ctx, app, client.Merge); err != nil {
|
||||||
@@ -423,6 +428,9 @@ func (r *Reconciler) patchStatus(ctx context.Context, app *v1beta1.Application,
|
|||||||
func (r *Reconciler) updateStatus(ctx context.Context, app *v1beta1.Application, phase common.ApplicationPhase) error {
|
func (r *Reconciler) updateStatus(ctx context.Context, app *v1beta1.Application, phase common.ApplicationPhase) error {
|
||||||
app.Status.Phase = phase
|
app.Status.Phase = phase
|
||||||
updateObservedGeneration(app)
|
updateObservedGeneration(app)
|
||||||
|
if oldApp, ok := originalAppFrom(ctx); ok && oldApp != nil && equality.Semantic.DeepEqual(oldApp.Status, app.Status) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
ctx, cancel := ctrlrec.NewReconcileTerminationContext(ctx)
|
ctx, cancel := ctrlrec.NewReconcileTerminationContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if !r.disableStatusUpdate {
|
if !r.disableStatusUpdate {
|
||||||
@@ -632,3 +640,23 @@ func (r *Reconciler) matchControllerRequirement(app *v1beta1.Application) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ComponentNamespaceContextKey is the key in context that defines the override namespace of component
|
||||||
|
ComponentNamespaceContextKey contextKey = iota
|
||||||
|
// ComponentContextKey is the key in context that records the component
|
||||||
|
ComponentContextKey
|
||||||
|
// ReplicaKeyContextKey is the key in context that records the replica key
|
||||||
|
ReplicaKeyContextKey
|
||||||
|
// OriginalAppKey is the key in the context that records the in coming original app
|
||||||
|
OriginalAppKey
|
||||||
|
)
|
||||||
|
|
||||||
|
func withOriginalApp(ctx context.Context, app *v1beta1.Application) context.Context {
|
||||||
|
return context.WithValue(ctx, OriginalAppKey, app.DeepCopy())
|
||||||
|
}
|
||||||
|
|
||||||
|
func originalAppFrom(ctx context.Context) (*v1beta1.Application, bool) {
|
||||||
|
app, ok := ctx.Value(OriginalAppKey).(*v1beta1.Application)
|
||||||
|
return app, ok
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ import (
|
|||||||
pkgutils "github.com/oam-dev/kubevela/pkg/utils"
|
pkgutils "github.com/oam-dev/kubevela/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type contextKey string
|
type contextKey int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ConfigMapKeyComponents is the key in ConfigMap Data field for containing data of components
|
// ConfigMapKeyComponents is the key in ConfigMap Data field for containing data of components
|
||||||
@@ -79,12 +79,6 @@ const (
|
|||||||
ManifestKeyTraits = "Traits"
|
ManifestKeyTraits = "Traits"
|
||||||
// ManifestKeyScopes is the key in Component Manifest for containing scope cr reference.
|
// ManifestKeyScopes is the key in Component Manifest for containing scope cr reference.
|
||||||
ManifestKeyScopes = "Scopes"
|
ManifestKeyScopes = "Scopes"
|
||||||
// ComponentNamespaceContextKey is the key in context that defines the override namespace of component
|
|
||||||
ComponentNamespaceContextKey = contextKey("component-namespace")
|
|
||||||
// ComponentContextKey is the key in context that records the component
|
|
||||||
ComponentContextKey = contextKey("component")
|
|
||||||
// ReplicaKeyContextKey is the key in context that records the replica key
|
|
||||||
ReplicaKeyContextKey = contextKey("replica-key")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const rolloutTraitName = "rollout"
|
const rolloutTraitName = "rollout"
|
||||||
|
|||||||
@@ -193,6 +193,9 @@ func (a *APIApplicator) Apply(ctx context.Context, desired client.Object, ao ...
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "cannot calculate patch by computing a three way diff")
|
return errors.Wrap(err, "cannot calculate patch by computing a three way diff")
|
||||||
}
|
}
|
||||||
|
if isEmptyPatch(patch) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if applyAct.dryRun {
|
if applyAct.dryRun {
|
||||||
return errors.Wrapf(a.c.Patch(ctx, desired, patch, client.DryRunAll), "cannot patch object")
|
return errors.Wrapf(a.c.Patch(ctx, desired, patch, client.DryRunAll), "cannot patch object")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ func TestAPIApplicator(t *testing.T) {
|
|||||||
return tc.args.existing, tc.args.creatorErr
|
return tc.args.existing, tc.args.creatorErr
|
||||||
}),
|
}),
|
||||||
patcher: patcherFn(func(c, m client.Object, a *applyAction) (client.Patch, error) {
|
patcher: patcherFn(func(c, m client.Object, a *applyAction) (client.Patch, error) {
|
||||||
return nil, tc.args.patcherErr
|
return client.RawPatch(types.MergePatchType, []byte(`err`)), tc.args.patcherErr
|
||||||
}),
|
}),
|
||||||
c: tc.c,
|
c: tc.c,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,3 +169,11 @@ func getOriginalConfiguration(obj runtime.Object) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return []byte(original), nil
|
return []byte(original), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isEmptyPatch(patch client.Patch) bool {
|
||||||
|
if patch == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
data, _ := patch.Data(nil)
|
||||||
|
return data != nil && string(data) == "{}"
|
||||||
|
}
|
||||||
|
|||||||
@@ -884,7 +884,7 @@ var _ = Describe("Test multicluster scenario", func() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.Expect(cnt).Should(Equal(2))
|
g.Expect(cnt).Should(Equal(2))
|
||||||
}).WithTimeout(10 * time.Second).WithPolling(2 * time.Second).Should(Succeed())
|
}).WithTimeout(30 * time.Second).WithPolling(2 * time.Second).Should(Succeed())
|
||||||
|
|
||||||
By("try update application again")
|
By("try update application again")
|
||||||
Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
|
Expect(k8sClient.Get(hubCtx, key, app)).Should(Succeed())
|
||||||
|
|||||||
Reference in New Issue
Block a user