From a7f950766af9340860ffb67bf3df9de9bacd33e5 Mon Sep 17 00:00:00 2001 From: lihanbo Date: Wed, 30 Jun 2021 20:06:53 +0800 Subject: [PATCH] resolve the 'AlreadyExist' conflicts in a 'Create' process Signed-off-by: lihanbo --- pkg/util/objectwatcher/objectwatcher.go | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pkg/util/objectwatcher/objectwatcher.go b/pkg/util/objectwatcher/objectwatcher.go index 31985bc71..13f6facbb 100644 --- a/pkg/util/objectwatcher/objectwatcher.go +++ b/pkg/util/objectwatcher/objectwatcher.go @@ -11,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -70,6 +71,12 @@ func (o *objectWatcherImpl) Create(cluster *v1alpha1.Cluster, desireObj *unstruc // users should resolve the conflict in person. clusterObj, err := dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Create(context.TODO(), desireObj, metav1.CreateOptions{}) if err != nil { + if apierrors.IsAlreadyExists(err) { + if err := o.resolveAlreadyExist(dynamicClusterClient, gvr, desireObj); err != nil { + return err + } + return nil + } klog.Errorf("Failed to create resource %v, err is %v ", desireObj.GetName(), err) return err } @@ -80,6 +87,31 @@ func (o *objectWatcherImpl) Create(cluster *v1alpha1.Cluster, desireObj *unstruc return nil } +// resolveAlreadyExist used to resolve the 'AlreadyExist' conflicts in a 'Create' process. +// The conflict may happen in following known scenarios: +// - 1. In a reconcile process, the execution controller successfully applied resource to member cluster but failed to update the work conditions(Applied=True), +// when reconcile again, the controller will try to apply(by create) the resource again. +// - 2. The resource already exist in the member cluster but it's not created by karmada. +func (o *objectWatcherImpl) resolveAlreadyExist(dynamicClusterClient *util.DynamicClusterClient, gvr schema.GroupVersionResource, desireObj *unstructured.Unstructured) error { + existObj, err := dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Get(context.TODO(), desireObj.GetName(), metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to get exist resource %s(%s/%s): %v", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), err) + } + + // Avoid updating resources that not managed by karmada. + if util.GetLabelValue(desireObj.GetLabels(), util.WorkNameLabel) != util.GetLabelValue(existObj.GetLabels(), util.WorkNameLabel) { + return fmt.Errorf("resource %s(%s/%s) already exist but not managed by karamda", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName()) + } + + _, err = dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Update(context.TODO(), desireObj, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("Failed to update exist resource %s(%s/%s), err is %v", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), err) + return fmt.Errorf("failed to update exist resource %s(%s/%s), err is %v", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), err) + } + + return nil +} + func (o *objectWatcherImpl) Update(cluster *v1alpha1.Cluster, desireObj, clusterObj *unstructured.Unstructured) error { dynamicClusterClient, err := o.ClusterClientSetFunc(cluster, o.KubeClientSet) if err != nil {