diff --git a/pkg/apis/work/v1alpha2/well_known_labels.go b/pkg/apis/work/v1alpha2/well_known_labels.go index a96a4d71c..5588d6dfc 100644 --- a/pkg/apis/work/v1alpha2/well_known_labels.go +++ b/pkg/apis/work/v1alpha2/well_known_labels.go @@ -26,3 +26,17 @@ const ( // WorkNameLabel is added to objects to specify associated Work's name. WorkNameLabel = "work.karmada.io/name" ) + +// Define resource conflict resolution +const ( + // ResourceConflictResolutionAnnotation is added to the resource template to specify how to resolve the conflict + // in case of resource already existing in member clusters. + // The valid value is: + // - overwrite: always overwrite the resource if already exist. The resource will be overwritten with the + // configuration from control plane. + // Note: Propagation of the resource template without this annotation will fail in case of already exists. + ResourceConflictResolutionAnnotation = "work.karmada.io/conflict-resolution" + + // ResourceConflictResolutionOverwrite is the value of ResourceConflictResolutionAnnotation, indicating the overwrite strategy. + ResourceConflictResolutionOverwrite = "overwrite" +) diff --git a/pkg/util/annotation.go b/pkg/util/annotation.go index 53e8f07a8..dd8c0556d 100644 --- a/pkg/util/annotation.go +++ b/pkg/util/annotation.go @@ -21,3 +21,11 @@ func MergeAnnotations(dst *unstructured.Unstructured, src *unstructured.Unstruct MergeAnnotation(dst, key, value) } } + +// GetAnnotationValue retrieves the value via 'annotationKey' if exist, otherwise returns an empty string. +func GetAnnotationValue(annotations map[string]string, annotationKey string) string { + if annotations == nil { + return "" + } + return annotations[annotationKey] +} diff --git a/pkg/util/objectwatcher/objectwatcher.go b/pkg/util/objectwatcher/objectwatcher.go index e19b99e33..e1ee454aa 100644 --- a/pkg/util/objectwatcher/objectwatcher.go +++ b/pkg/util/objectwatcher/objectwatcher.go @@ -16,6 +16,7 @@ import ( configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1" workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" "github.com/karmada-io/karmada/pkg/resourceinterpreter" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/restmapper" @@ -84,12 +85,23 @@ func (o *objectWatcherImpl) Create(clusterName string, desireObj *unstructured.U return fmt.Errorf("failed to get exist resource(kind=%s, %s/%s) in cluster %v: %v", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), clusterName, err) } - // Avoid updating resources that not managed by karmada. - if util.GetLabelValue(desireObj.GetLabels(), workv1alpha1.WorkNameLabel) != util.GetLabelValue(existObj.GetLabels(), workv1alpha1.WorkNameLabel) { - return fmt.Errorf("resource(kind=%s, %s/%s) already exist in cluster %v but not managed by karamda", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), clusterName) + // If the existing resource is managed by Karmada, then just update it. + if util.GetLabelValue(desireObj.GetLabels(), workv1alpha1.WorkNameLabel) == util.GetLabelValue(existObj.GetLabels(), workv1alpha1.WorkNameLabel) { + return o.Update(clusterName, desireObj, existObj) } - return o.Update(clusterName, desireObj, existObj) + // The existing resource is not managed by Karmada, then we should consult conflict resolution instruction in annotation. + switch util.GetAnnotationValue(desireObj.GetAnnotations(), workv1alpha2.ResourceConflictResolutionAnnotation) { + case workv1alpha2.ResourceConflictResolutionOverwrite: + klog.Infof("Overwriting the resource(kind=%s, %s/%s) as %s=%s", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), + workv1alpha2.ResourceConflictResolutionAnnotation, workv1alpha2.ResourceConflictResolutionOverwrite) + return o.Update(clusterName, desireObj, existObj) + default: + // The existing resource is not managed by Karmada, and no conflict resolution found, avoid updating the existing resource by default. + return fmt.Errorf("resource(kind=%s, %s/%s) already exist in cluster %v and the %s strategy value is empty, karmada will not manage this resource", + desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), clusterName, workv1alpha2.ResourceConflictResolutionAnnotation, + ) + } } klog.Errorf("Failed to create resource(kind=%s, %s/%s) in cluster %s, err is %v ", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), clusterName, err) return err