diff --git a/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go b/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go index e088d8636..3792118fc 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go +++ b/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go @@ -27,6 +27,8 @@ import ( "github.com/pkg/errors" kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -77,13 +79,13 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { app.Status.Phase = v1alpha2.ApplicationRollingOut app.Status.SetConditions(readyCondition("Rolling")) // do not process apps still in rolling out - return ctrl.Result{RequeueAfter: RolloutReconcileWaitTime}, r.Status().Update(ctx, app) + return ctrl.Result{RequeueAfter: RolloutReconcileWaitTime}, r.UpdateStatus(ctx, app) } applog.Info("Start Rendering") app.Status.Phase = v1alpha2.ApplicationRendering - handler := &appHandler{r.Client, app, applog} + handler := &appHandler{r, app, applog} app.Status.Conditions = []v1alpha1.Condition{} @@ -149,7 +151,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { }) } app.Status.Components = refComps - return ctrl.Result{}, r.Status().Update(ctx, app) + return ctrl.Result{}, r.UpdateStatus(ctx, app) } // SetupWithManager install to manager @@ -160,6 +162,18 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } +// UpdateStatus updates v1alpha2.Application's Status with retry.RetryOnConflict +func (r *Reconciler) UpdateStatus(ctx context.Context, app *v1alpha2.Application, opts ...client.UpdateOption) error { + status := app.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = r.Get(ctx, types.NamespacedName{Namespace: app.Namespace, Name: app.Name}, app); err != nil { + return + } + app.Status = status + return r.Status().Update(ctx, app, opts...) + }) +} + // Setup adds a controller that reconciles ApplicationDeployment. func Setup(mgr ctrl.Manager, _ core.Args, _ logging.Logger) error { dm, err := discoverymapper.New(mgr.GetConfig()) diff --git a/pkg/controller/core.oam.dev/v1alpha2/application/apply.go b/pkg/controller/core.oam.dev/v1alpha2/application/apply.go index f79f81302..cce108aa9 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/application/apply.go +++ b/pkg/controller/core.oam.dev/v1alpha2/application/apply.go @@ -40,13 +40,13 @@ func readyCondition(tpy string) runtimev1alpha1.Condition { } type appHandler struct { - c client.Client + r *Reconciler app *v1alpha2.Application l logr.Logger } func (ret *appHandler) Err(err error) (ctrl.Result, error) { - nerr := ret.c.Status().Update(context.Background(), ret.app) + nerr := ret.r.UpdateStatus(context.Background(), ret.app) if err == nil && nerr == nil { return ctrl.Result{}, nil } @@ -92,7 +92,7 @@ func (ret *appHandler) statusAggregate(appfile *appfile.Appfile) ([]v1alpha2.App } } - workloadHealth, err := wl.EvalHealth(pCtx, ret.c, ret.app.Namespace) + workloadHealth, err := wl.EvalHealth(pCtx, ret.r, ret.app.Namespace) if err != nil { return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appfile.Name, wl.Name) } @@ -101,7 +101,7 @@ func (ret *appHandler) statusAggregate(appfile *appfile.Appfile) ([]v1alpha2.App status.Healthy = false healthy = false } - status.Message, err = wl.EvalStatus(pCtx, ret.c, ret.app.Namespace) + status.Message, err = wl.EvalStatus(pCtx, ret.r, ret.app.Namespace) if err != nil { return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, evaluate workload status message error", appfile.Name, wl.Name) } @@ -111,7 +111,7 @@ func (ret *appHandler) statusAggregate(appfile *appfile.Appfile) ([]v1alpha2.App Type: trait.Name, Healthy: true, } - traitHealth, err := trait.EvalHealth(pCtx, ret.c, ret.app.Namespace) + traitHealth, err := trait.EvalHealth(pCtx, ret.r, ret.app.Namespace) if err != nil { return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, check health error", appfile.Name, wl.Name, trait.Name) } @@ -120,7 +120,7 @@ func (ret *appHandler) statusAggregate(appfile *appfile.Appfile) ([]v1alpha2.App traitStatus.Healthy = false healthy = false } - traitStatus.Message, err = trait.EvalStatus(pCtx, ret.c, ret.app.Namespace) + traitStatus.Message, err = trait.EvalStatus(pCtx, ret.r, ret.app.Namespace) if err != nil { return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, evaluate status message error", appfile.Name, wl.Name, trait.Name) } @@ -167,12 +167,12 @@ func CreateOrUpdateAppConfig(ctx context.Context, client client.Client, appConfi // Sync perform synchronization operations func (ret *appHandler) Sync(ctx context.Context, ac *v1alpha2.ApplicationConfiguration, comps []*v1alpha2.Component) error { for _, comp := range comps { - if err := CreateOrUpdateComponent(ctx, ret.c, comp.DeepCopy()); err != nil { + if err := CreateOrUpdateComponent(ctx, ret.r, comp.DeepCopy()); err != nil { return err } } - if err := CreateOrUpdateAppConfig(ctx, ret.c, ac); err != nil { + if err := CreateOrUpdateAppConfig(ctx, ret.r, ac); err != nil { return err } @@ -191,7 +191,7 @@ func (ret *appHandler) Sync(ctx context.Context, ac *v1alpha2.ApplicationConfigu } // Component not exits in current Application, should be deleted var oldC = &v1alpha2.Component{ObjectMeta: metav1.ObjectMeta{Name: comp.Name, Namespace: ac.Namespace}} - if err := ret.c.Delete(ctx, oldC); err != nil { + if err := ret.r.Delete(ctx, oldC); err != nil { return err } } diff --git a/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/applicationconfiguration.go b/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/applicationconfiguration.go index 8b9c63d28..3b2d588eb 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/applicationconfiguration.go +++ b/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/applicationconfiguration.go @@ -27,6 +27,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -245,7 +247,7 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco "error", err, "requeue-after", result.RequeueAfter) r.record.Event(ac, event.Warning(reasonCannotFinalizeWorkloads, err)) ac.SetConditions(v1alpha1.ReconcileError(errors.Wrap(err, errFinalizeWorkloads))) - return reconcile.Result{}, errors.Wrap(r.client.Status().Update(ctx, ac), errUpdateAppConfigStatus) + return reconcile.Result{}, errors.Wrap(r.UpdateStatus(ctx, ac), errUpdateAppConfigStatus) } return reconcile.Result{}, errors.Wrap(r.client.Update(ctx, ac), errUpdateAppConfigStatus) } @@ -260,12 +262,12 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco r.record.Event(ac, event.Warning(reasonCannotExecutePosthooks, err)) ac.SetConditions(v1alpha1.ReconcileError(errors.Wrap(err, errExecutePosthooks))) result = exeResult - returnErr = errors.Wrap(r.client.Status().Update(ctx, ac), errUpdateAppConfigStatus) + returnErr = errors.Wrap(r.UpdateStatus(ctx, ac), errUpdateAppConfigStatus) return } r.record.Event(ac, event.Normal(reasonExecutePosthook, "Successfully executed a posthook", "posthook name", name)) } - returnErr = errors.Wrap(r.client.Status().Update(ctx, ac), errUpdateAppConfigStatus) + returnErr = errors.Wrap(r.UpdateStatus(ctx, ac), errUpdateAppConfigStatus) // Make sure if error occurs, reconcile will not happen too frequency if returnErr != nil && result.RequeueAfter < shortWait { @@ -280,7 +282,7 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco log.Debug("Failed to execute pre-hooks", "hook name", name, "error", err, "requeue-after", result.RequeueAfter) r.record.Event(ac, event.Warning(reasonCannotExecutePrehooks, err)) ac.SetConditions(v1alpha1.ReconcileError(errors.Wrap(err, errExecutePrehooks))) - return result, errors.Wrap(r.client.Status().Update(ctx, ac), errUpdateAppConfigStatus) + return result, errors.Wrap(r.UpdateStatus(ctx, ac), errUpdateAppConfigStatus) } r.record.Event(ac, event.Normal(reasonExecutePrehook, "Successfully executed a prehook", "prehook name ", name)) } @@ -292,7 +294,7 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco log.Info("Cannot render components", "error", err, "requeue-after", time.Now().Add(shortWait)) r.record.Event(ac, event.Warning(reasonCannotRenderComponents, err)) ac.SetConditions(v1alpha1.ReconcileError(errors.Wrap(err, errRenderComponents))) - return errResult, errors.Wrap(r.client.Status().Update(ctx, ac), errUpdateAppConfigStatus) + return errResult, errors.Wrap(r.UpdateStatus(ctx, ac), errUpdateAppConfigStatus) } log.Debug("Successfully rendered components", "workloads", len(workloads)) r.record.Event(ac, event.Normal(reasonRenderComponents, "Successfully rendered components", "workloads", strconv.Itoa(len(workloads)))) @@ -302,7 +304,7 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco log.Debug("Cannot apply components", "error", err, "requeue-after", time.Now().Add(shortWait)) r.record.Event(ac, event.Warning(reasonCannotApplyComponents, err)) ac.SetConditions(v1alpha1.ReconcileError(errors.Wrap(err, errApplyComponents))) - return errResult, errors.Wrap(r.client.Status().Update(ctx, ac), errUpdateAppConfigStatus) + return errResult, errors.Wrap(r.UpdateStatus(ctx, ac), errUpdateAppConfigStatus) } log.Debug("Successfully applied components", "workloads", len(workloads)) r.record.Event(ac, event.Normal(reasonApplyComponents, "Successfully applied components", "workloads", strconv.Itoa(len(workloads)))) @@ -322,7 +324,7 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco log.Debug("Cannot garbage collect component", "error", err, "requeue-after", time.Now().Add(shortWait)) record.Event(ac, event.Warning(reasonCannotGGComponents, err)) ac.SetConditions(v1alpha1.ReconcileError(errors.Wrap(err, errGCComponent))) - return errResult, errors.Wrap(r.client.Status().Update(ctx, ac), errUpdateAppConfigStatus) + return errResult, errors.Wrap(r.UpdateStatus(ctx, ac), errUpdateAppConfigStatus) } log.Debug("Garbage collected resource") record.Event(ac, event.Normal(reasonGGComponent, "Successfully garbage collected component")) @@ -342,6 +344,18 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco return reconcile.Result{RequeueAfter: waitTime}, nil } +// UpdateStatus updates v1alpha2.ApplicationConfiguration's Status with retry.RetryOnConflict +func (r *OAMApplicationReconciler) UpdateStatus(ctx context.Context, ac *v1alpha2.ApplicationConfiguration, opts ...client.UpdateOption) error { + status := ac.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = r.client.Get(ctx, types.NamespacedName{Namespace: ac.Namespace, Name: ac.Name}, ac); err != nil { + return + } + ac.Status = status + return r.client.Status().Update(ctx, ac, opts...) + }) +} + func (r *OAMApplicationReconciler) updateStatus(ctx context.Context, ac, acPatch *v1alpha2.ApplicationConfiguration, workloads []Workload) { ac.Status.Workloads = make([]v1alpha2.WorkloadStatus, len(workloads)) historyWorkloads := make([]v1alpha2.HistoryWorkload, 0) diff --git a/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/component.go b/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/component.go index a9a086def..a05a49453 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/component.go +++ b/pkg/controller/core.oam.dev/v1alpha2/applicationconfiguration/component.go @@ -11,6 +11,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" "k8s.io/client-go/util/workqueue" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" @@ -191,7 +192,7 @@ func (c *ComponentHandler) createControllerRevision(mt metav1.Object, obj runtim return nil, false } - err = c.Client.Status().Update(context.Background(), comp) + err = c.UpdateStatus(context.Background(), comp) if err != nil { c.Logger.Info(fmt.Sprintf("update component status latestRevision %s err %v", revisionName, err), "componentName", mt.GetName()) return nil, false @@ -277,6 +278,18 @@ func (c *ComponentHandler) cleanupControllerRevision(curComp *v1alpha2.Component return nil } +// UpdateStatus updates v1alpha2.Component's Status with retry.RetryOnConflict +func (c *ComponentHandler) UpdateStatus(ctx context.Context, comp *v1alpha2.Component, opts ...client.UpdateOption) error { + status := comp.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = c.Client.Get(ctx, types.NamespacedName{Namespace: comp.Namespace, Name: comp.Name}, comp); err != nil { + return + } + comp.Status = status + return c.Client.Status().Update(ctx, comp, opts...) + }) +} + // ConstructRevisionName will generate revisionName from componentName // will be -v, for example: comp-v1 func ConstructRevisionName(componentName string, revision int64) string { diff --git a/pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope/healthscope_controller.go b/pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope/healthscope_controller.go index a63efe935..a6615db6a 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope/healthscope_controller.go +++ b/pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope/healthscope_controller.go @@ -23,6 +23,8 @@ import ( "time" "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -172,7 +174,7 @@ func (r *Reconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) hs.Status.ScopeHealthCondition = scopeCondition hs.Status.WorkloadHealthConditions = wlConditions - return reconcile.Result{RequeueAfter: interval - elapsed}, errors.Wrap(r.client.Status().Update(ctx, hs), errUpdateHealthScopeStatus) + return reconcile.Result{RequeueAfter: interval - elapsed}, errors.Wrap(r.UpdateStatus(ctx, hs), errUpdateHealthScopeStatus) } // GetScopeHealthStatus get the status of the healthscope based on workload resources. @@ -257,3 +259,15 @@ func (r *Reconciler) GetScopeHealthStatus(ctx context.Context, healthScope *v1al return scopeCondition, workloadHealthConditions } + +// UpdateStatus updates v1alpha2.HealthScope's Status with retry.RetryOnConflict +func (r *Reconciler) UpdateStatus(ctx context.Context, hs *v1alpha2.HealthScope, opts ...client.UpdateOption) error { + status := hs.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = r.client.Get(ctx, types.NamespacedName{Namespace: hs.Namespace, Name: hs.Name}, hs); err != nil { + return + } + hs.Status = status + return r.client.Status().Update(ctx, hs, opts...) + }) +} diff --git a/pkg/controller/core.oam.dev/v1alpha2/core/workloads/containerizedworkload/containerizedworkload_controller.go b/pkg/controller/core.oam.dev/v1alpha2/core/workloads/containerizedworkload/containerizedworkload_controller.go index e83a484f1..0b382b283 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/core/workloads/containerizedworkload/containerizedworkload_controller.go +++ b/pkg/controller/core.oam.dev/v1alpha2/core/workloads/containerizedworkload/containerizedworkload_controller.go @@ -29,6 +29,8 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -172,12 +174,24 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { }, ) - if err := r.Status().Update(ctx, &workload); err != nil { + if err := r.UpdateStatus(ctx, &workload); err != nil { return util.ReconcileWaitResult, err } return ctrl.Result{}, util.PatchCondition(ctx, r, &workload, cpv1alpha1.ReconcileSuccess()) } +// UpdateStatus updates v1alpha2.ContainerizedWorkload's Status with retry.RetryOnConflict +func (r *Reconciler) UpdateStatus(ctx context.Context, workload *v1alpha2.ContainerizedWorkload, opts ...client.UpdateOption) error { + status := workload.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = r.Get(ctx, types.NamespacedName{Namespace: workload.Namespace, Name: workload.Name}, workload); err != nil { + return + } + workload.Status = status + return r.Status().Update(ctx, workload, opts...) + }) +} + // SetupWithManager setups up k8s controller. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { src := &v1alpha2.ContainerizedWorkload{} diff --git a/pkg/controller/standard.oam.dev/v1alpha1/metrics/metricstrait_controller.go b/pkg/controller/standard.oam.dev/v1alpha1/metrics/metricstrait_controller.go index c7e20d183..2779a3e1b 100644 --- a/pkg/controller/standard.oam.dev/v1alpha1/metrics/metricstrait_controller.go +++ b/pkg/controller/standard.oam.dev/v1alpha1/metrics/metricstrait_controller.go @@ -31,7 +31,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/util/retry" "k8s.io/utils/pointer" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -163,7 +165,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { r.gcOrphanServiceMonitor(ctx, mLog, &metricsTrait) (&metricsTrait).SetConditions(cpv1alpha1.ReconcileSuccess()) - return ctrl.Result{}, errors.Wrap(r.Status().Update(ctx, &metricsTrait), common.ErrUpdateStatus) + return ctrl.Result{}, errors.Wrap(r.UpdateStatus(ctx, &metricsTrait), common.ErrUpdateStatus) } // fetch the label of the service that is associated with the workload @@ -336,6 +338,18 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } +// UpdateStatus updates v1alpha1.MetricsTrait's Status with retry.RetryOnConflict +func (r *Reconciler) UpdateStatus(ctx context.Context, mt *v1alpha1.MetricsTrait, opts ...client.UpdateOption) error { + status := mt.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = r.Get(ctx, types.NamespacedName{Namespace: mt.Namespace, Name: mt.Name}, mt); err != nil { + return + } + mt.Status = status + return r.Status().Update(ctx, mt, opts...) + }) +} + // Setup adds a controller that reconciles MetricsTrait. func Setup(mgr ctrl.Manager) error { dm, err := discoverymapper.New(mgr.GetConfig()) diff --git a/pkg/controller/standard.oam.dev/v1alpha1/podspecworkload/podspecworkload_controller.go b/pkg/controller/standard.oam.dev/v1alpha1/podspecworkload/podspecworkload_controller.go index 5a0b83b0e..6d71459e5 100644 --- a/pkg/controller/standard.oam.dev/v1alpha1/podspecworkload/podspecworkload_controller.go +++ b/pkg/controller/standard.oam.dev/v1alpha1/podspecworkload/podspecworkload_controller.go @@ -30,7 +30,9 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -151,7 +153,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { }) } - if err := r.Status().Update(ctx, &workload); err != nil { + if err := r.UpdateStatus(ctx, &workload); err != nil { return util.ReconcileWaitResult, err } return ctrl.Result{}, util.PatchCondition(ctx, r, &workload, cpv1alpha1.ReconcileSuccess()) @@ -277,6 +279,18 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } +// UpdateStatus updates *v1alpha1.PodSpecWorkload's Status with retry.RetryOnConflict +func (r *Reconciler) UpdateStatus(ctx context.Context, workload *v1alpha1.PodSpecWorkload, opts ...client.UpdateOption) error { + status := workload.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = r.Get(ctx, types.NamespacedName{Namespace: workload.Namespace, Name: workload.Name}, workload); err != nil { + return + } + workload.Status = status + return r.Status().Update(ctx, workload, opts...) + }) +} + // Setup adds a controller that reconciles PodSpecWorkload. func Setup(mgr ctrl.Manager) error { reconciler := Reconciler{ diff --git a/pkg/controller/standard.oam.dev/v1alpha1/routes/route_controller.go b/pkg/controller/standard.oam.dev/v1alpha1/routes/route_controller.go index e91678501..ec343d6e9 100644 --- a/pkg/controller/standard.oam.dev/v1alpha1/routes/route_controller.go +++ b/pkg/controller/standard.oam.dev/v1alpha1/routes/route_controller.go @@ -23,11 +23,10 @@ import ( "reflect" "time" - "github.com/oam-dev/kubevela/pkg/controller/utils" - standardv1alpha1 "github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1" "github.com/oam-dev/kubevela/pkg/controller/common" "github.com/oam-dev/kubevela/pkg/controller/standard.oam.dev/v1alpha1/routes/ingress" + "github.com/oam-dev/kubevela/pkg/controller/utils" runtimev1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1" "github.com/crossplane/crossplane-runtime/pkg/event" @@ -39,7 +38,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/util/retry" "k8s.io/utils/pointer" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -146,9 +147,9 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { routeTrait.Status.Status, conditions = routeIngress.CheckStatus(&routeTrait) routeTrait.Status.Conditions = conditions if routeTrait.Status.Status != ingress.StatusReady { - return ctrl.Result{RequeueAfter: requeueNotReady}, r.Status().Update(ctx, &routeTrait) + return ctrl.Result{RequeueAfter: requeueNotReady}, r.UpdateStatus(ctx, &routeTrait) } - err = r.Status().Update(ctx, &routeTrait) + err = r.UpdateStatus(ctx, &routeTrait) if err != nil { return oamutil.ReconcileWaitResult, err } @@ -247,6 +248,18 @@ func (r *Reconciler) fillBackendByCreatedService(ctx context.Context, mLog logr. }, nil } +// UpdateStatus updates standardv1alpha1.Route's Status with retry.RetryOnConflict +func (r *Reconciler) UpdateStatus(ctx context.Context, route *standardv1alpha1.Route, opts ...client.UpdateOption) error { + status := route.DeepCopy().Status + return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { + if err = r.Get(ctx, types.NamespacedName{Namespace: route.Namespace, Name: route.Name}, route); err != nil { + return + } + route.Status = status + return r.Status().Update(ctx, route, opts...) + }) +} + // DiscoverPortsLabel assume the workload or it's childResource will always having spec.template as PodTemplate if discoverable func DiscoverPortsLabel(ctx context.Context, workload *unstructured.Unstructured, r client.Reader, dm discoverymapper.DiscoveryMapper, childResources []*unstructured.Unstructured) ([]intstr.IntOrString, map[string]string, error) {