Merge pull request #4199 from jwcesign/add-id-label
feat: add resource id label
This commit is contained in:
commit
55547b2acf
2
go.mod
2
go.mod
|
@ -11,6 +11,7 @@ require (
|
|||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/kr/pretty v0.3.1
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
|
@ -100,7 +101,6 @@ require (
|
|||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
|
||||
|
|
|
@ -17,6 +17,20 @@ limitations under the License.
|
|||
package v1alpha1
|
||||
|
||||
const (
|
||||
// PropagationPolicyPermanentIDLabel is the identifier of a PropagationPolicy object.
|
||||
// Karmada generates a unique identifier, such as metadata.UUID, for each PropagationPolicy object.
|
||||
// This identifier will be used as a label selector to locate corresponding resources, such as ResourceBinding.
|
||||
// The reason for generating a new unique identifier instead of simply using metadata.UUID is because:
|
||||
// In backup scenarios, when applying the backup resource manifest in a new cluster, the UUID may change.
|
||||
PropagationPolicyPermanentIDLabel = "propagationpolicy.karmada.io/permanent-id"
|
||||
|
||||
// ClusterPropagationPolicyPermanentIDLabel is the identifier of a ClusterPropagationPolicy object.
|
||||
// Karmada generates a unique identifier, such as metadata.UUID, for each ClusterPropagationPolicy object.
|
||||
// This identifier will be used as a label selector to locate corresponding resources, such as ResourceBinding.
|
||||
// The reason for generating a new unique identifier instead of simply using metadata.UUID is because:
|
||||
// In backup scenarios, when applying the backup resource manifest in a new cluster, the UUID may change.
|
||||
ClusterPropagationPolicyPermanentIDLabel = "clusterpropagationpolicy.karmada.io/permanent-id"
|
||||
|
||||
// PropagationPolicyUIDLabel is the uid of PropagationPolicy object.
|
||||
PropagationPolicyUIDLabel = "propagationpolicy.karmada.io/uid"
|
||||
|
||||
|
|
|
@ -17,6 +17,23 @@ limitations under the License.
|
|||
package v1alpha2
|
||||
|
||||
const (
|
||||
// ResourceBindingPermanentIDLabel is the identifier of a ResourceBinding object.
|
||||
// Karmada generates a unique identifier, such as metadata.UUID, for each ResourceBinding object.
|
||||
// This identifier will be used as a label selector to locate corresponding resources, such as Work.
|
||||
// The reason for generating a new unique identifier instead of simply using metadata.UUID is because:
|
||||
// In backup scenarios, when applying the backup resource manifest in a new cluster, the UUID may change.
|
||||
ResourceBindingPermanentIDLabel = "resourcebinding.karmada.io/permanent-id"
|
||||
|
||||
// ClusterResourceBindingPermanentIDLabel is the identifier of a ClusterResourceBinding object.
|
||||
// Karmada generates a unique identifier, such as metadata.UUID, for each ClusterResourceBinding object.
|
||||
// This identifier will be used as a label selector to locate corresponding resources, such as Work.
|
||||
// The reason for generating a new unique identifier instead of simply using metadata.UUID is because:
|
||||
// In backup scenarios, when applying the backup resource manifest in a new cluster, the UUID may change.
|
||||
ClusterResourceBindingPermanentIDLabel = "clusterresourcebinding.karmada.io/permanent-id"
|
||||
|
||||
// WorkPermanentIDLabel is the ID of Work object.
|
||||
WorkPermanentIDLabel = "work.karmada.io/permanent-id"
|
||||
|
||||
// ResourceBindingUIDLabel is the UID of ResourceBinding object.
|
||||
ResourceBindingUIDLabel = "resourcebinding.karmada.io/uid"
|
||||
|
||||
|
|
|
@ -159,15 +159,23 @@ func mergeLabel(workload *unstructured.Unstructured, workNamespace string, bindi
|
|||
util.MergeLabel(workload, workv1alpha1.WorkNameLabel, names.GenerateWorkName(workload.GetKind(), workload.GetName(), workload.GetNamespace()))
|
||||
util.MergeLabel(workload, util.ManagedByKarmadaLabel, util.ManagedByKarmadaLabelValue)
|
||||
if scope == apiextensionsv1.NamespaceScoped {
|
||||
util.RemoveLabels(workload, workv1alpha2.ResourceBindingUIDLabel)
|
||||
|
||||
bindingID := util.GetLabelValue(binding.GetLabels(), workv1alpha2.ResourceBindingPermanentIDLabel)
|
||||
util.MergeLabel(workload, workv1alpha2.ResourceBindingReferenceKey, names.GenerateBindingReferenceKey(binding.GetNamespace(), binding.GetName()))
|
||||
util.MergeLabel(workload, workv1alpha2.ResourceBindingUIDLabel, string(binding.GetUID()))
|
||||
util.MergeLabel(workload, workv1alpha2.ResourceBindingPermanentIDLabel, bindingID)
|
||||
|
||||
workLabel[workv1alpha2.ResourceBindingReferenceKey] = names.GenerateBindingReferenceKey(binding.GetNamespace(), binding.GetName())
|
||||
workLabel[workv1alpha2.ResourceBindingUIDLabel] = string(binding.GetUID())
|
||||
workLabel[workv1alpha2.ResourceBindingPermanentIDLabel] = bindingID
|
||||
} else {
|
||||
util.RemoveLabels(workload, workv1alpha2.ClusterResourceBindingUIDLabel)
|
||||
|
||||
bindingID := util.GetLabelValue(binding.GetLabels(), workv1alpha2.ClusterResourceBindingPermanentIDLabel)
|
||||
util.MergeLabel(workload, workv1alpha2.ClusterResourceBindingReferenceKey, names.GenerateBindingReferenceKey("", binding.GetName()))
|
||||
util.MergeLabel(workload, workv1alpha2.ClusterResourceBindingUIDLabel, string(binding.GetUID()))
|
||||
util.MergeLabel(workload, workv1alpha2.ClusterResourceBindingPermanentIDLabel, bindingID)
|
||||
|
||||
workLabel[workv1alpha2.ClusterResourceBindingReferenceKey] = names.GenerateBindingReferenceKey("", binding.GetName())
|
||||
workLabel[workv1alpha2.ClusterResourceBindingUIDLabel] = string(binding.GetUID())
|
||||
workLabel[workv1alpha2.ClusterResourceBindingPermanentIDLabel] = bindingID
|
||||
}
|
||||
return workLabel
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
||||
|
@ -104,7 +103,7 @@ func Test_mergeTargetClusters(t *testing.T) {
|
|||
func Test_mergeLabel(t *testing.T) {
|
||||
namespace := "fake-ns"
|
||||
bindingName := "fake-bindingName"
|
||||
rbUID := "93162d3c-ee8e-4995-9034-05f4d5d2c2b9"
|
||||
rbID := "93162d3c-ee8e-4995-9034-05f4d5d2c2b9"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -131,13 +130,15 @@ func Test_mergeLabel(t *testing.T) {
|
|||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bindingName,
|
||||
Namespace: namespace,
|
||||
UID: types.UID(rbUID),
|
||||
Labels: map[string]string{
|
||||
workv1alpha2.ResourceBindingPermanentIDLabel: rbID,
|
||||
},
|
||||
},
|
||||
},
|
||||
scope: v1.NamespaceScoped,
|
||||
want: map[string]string{
|
||||
workv1alpha2.ResourceBindingUIDLabel: rbUID,
|
||||
workv1alpha2.ResourceBindingReferenceKey: names.GenerateBindingReferenceKey(namespace, bindingName),
|
||||
workv1alpha2.ResourceBindingPermanentIDLabel: rbID,
|
||||
workv1alpha2.ResourceBindingReferenceKey: names.GenerateBindingReferenceKey(namespace, bindingName),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -154,13 +155,15 @@ func Test_mergeLabel(t *testing.T) {
|
|||
binding: &workv1alpha2.ClusterResourceBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bindingName,
|
||||
UID: types.UID(rbUID),
|
||||
Labels: map[string]string{
|
||||
workv1alpha2.ClusterResourceBindingPermanentIDLabel: rbID,
|
||||
},
|
||||
},
|
||||
},
|
||||
scope: v1.ClusterScoped,
|
||||
want: map[string]string{
|
||||
workv1alpha2.ClusterResourceBindingUIDLabel: rbUID,
|
||||
workv1alpha2.ClusterResourceBindingReferenceKey: names.GenerateBindingReferenceKey("", bindingName),
|
||||
workv1alpha2.ClusterResourceBindingPermanentIDLabel: rbID,
|
||||
workv1alpha2.ClusterResourceBindingReferenceKey: names.GenerateBindingReferenceKey("", bindingName),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -206,12 +206,12 @@ func (c *Controller) syncToClusters(clusterName string, work *workv1alpha1.Work)
|
|||
for _, manifest := range work.Spec.Workload.Manifests {
|
||||
workload := &unstructured.Unstructured{}
|
||||
err := workload.UnmarshalJSON(manifest.Raw)
|
||||
util.MergeLabel(workload, workv1alpha2.WorkUIDLabel, string(work.UID))
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to unmarshal workload, error is: %v", err)
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
util.MergeLabel(workload, workv1alpha2.WorkPermanentIDLabel, util.GetLabelValue(work.Labels, workv1alpha2.WorkPermanentIDLabel))
|
||||
|
||||
if err = c.tryCreateOrUpdateWorkload(clusterName, workload); err != nil {
|
||||
klog.Errorf("Failed to create or update resource(%v/%v) in the given member cluster %s, err is %v", workload.GetNamespace(), workload.GetName(), clusterName, err)
|
||||
|
|
|
@ -87,7 +87,7 @@ func (r *HPAReplicasSyncer) Generic(e event.GenericEvent) bool {
|
|||
}
|
||||
|
||||
func hasBeenPropagated(hpa *autoscalingv2.HorizontalPodAutoscaler) bool {
|
||||
_, ppExist := hpa.GetLabels()[policyv1alpha1.PropagationPolicyUIDLabel]
|
||||
_, cppExist := hpa.GetLabels()[policyv1alpha1.ClusterPropagationPolicyUIDLabel]
|
||||
_, ppExist := hpa.GetLabels()[policyv1alpha1.PropagationPolicyNameLabel]
|
||||
_, cppExist := hpa.GetLabels()[policyv1alpha1.ClusterPropagationPolicyLabel]
|
||||
return ppExist || cppExist
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
|
@ -61,6 +62,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// bindingDependedIdLabelKey is the resoruce id of the independent binding which the attached binding depends on.
|
||||
bindingDependedIdLabelKey = "resourcebinding.karmada.io/depended-id"
|
||||
|
||||
// bindingDependedByLabelKeyPrefix is the prefix to a label key specifying an attached binding referred by which independent binding.
|
||||
// the key is in the label of an attached binding which should be unique, because resource like secret can be referred by multiple deployments.
|
||||
bindingDependedByLabelKeyPrefix = "resourcebinding.karmada.io/depended-by-"
|
||||
|
@ -514,19 +518,14 @@ func (d *DependenciesDistributor) removeScheduleResultFromAttachedBindings(bindi
|
|||
}
|
||||
|
||||
func (d *DependenciesDistributor) createOrUpdateAttachedBinding(attachedBinding *workv1alpha2.ResourceBinding) error {
|
||||
if err := d.Client.Create(context.TODO(), attachedBinding); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
klog.Infof("Failed to create resource binding(%s/%s): %v", attachedBinding.Namespace, attachedBinding.Name, err)
|
||||
return err
|
||||
existBinding := &workv1alpha2.ResourceBinding{}
|
||||
key := client.ObjectKeyFromObject(attachedBinding)
|
||||
err := d.Client.Get(context.TODO(), key, existBinding)
|
||||
if err == nil {
|
||||
if util.GetLabelValue(existBinding.Labels, workv1alpha2.ResourceBindingPermanentIDLabel) == "" {
|
||||
existBinding.Labels = util.DedupeAndMergeLabels(existBinding.Labels,
|
||||
map[string]string{workv1alpha2.ResourceBindingPermanentIDLabel: uuid.New().String()})
|
||||
}
|
||||
|
||||
existBinding := &workv1alpha2.ResourceBinding{}
|
||||
key := client.ObjectKeyFromObject(attachedBinding)
|
||||
if err := d.Client.Get(context.TODO(), key, existBinding); err != nil {
|
||||
klog.Infof("Failed to get resource binding(%s/%s): %v", attachedBinding.Namespace, attachedBinding.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
existBinding.Spec.RequiredBy = mergeBindingSnapshot(existBinding.Spec.RequiredBy, attachedBinding.Spec.RequiredBy)
|
||||
existBinding.Labels = util.DedupeAndMergeLabels(existBinding.Labels, attachedBinding.Labels)
|
||||
existBinding.Spec.Resource = attachedBinding.Spec.Resource
|
||||
|
@ -536,6 +535,17 @@ func (d *DependenciesDistributor) createOrUpdateAttachedBinding(attachedBinding
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !apierrors.IsNotFound(err) {
|
||||
klog.Infof("Failed to get resource binding(%s/%s): %v", attachedBinding.Namespace, attachedBinding.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
attachedBinding.Labels = util.DedupeAndMergeLabels(attachedBinding.Labels,
|
||||
map[string]string{workv1alpha2.ResourceBindingPermanentIDLabel: uuid.New().String()})
|
||||
if err := d.Client.Create(context.TODO(), attachedBinding); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -646,6 +656,8 @@ func buildAttachedBinding(binding *workv1alpha2.ResourceBinding, object *unstruc
|
|||
Clusters: binding.Spec.Clusters,
|
||||
})
|
||||
|
||||
policyID := util.GetLabelValue(binding.Labels, workv1alpha2.ResourceBindingPermanentIDLabel)
|
||||
dependedLabels = util.DedupeAndMergeLabels(dependedLabels, map[string]string{bindingDependedIdLabelKey: policyID})
|
||||
return &workv1alpha2.ResourceBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: names.GenerateBindingName(object.GetKind(), object.GetName()),
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
|
@ -411,15 +412,16 @@ func (d *ResourceDetector) ApplyPolicy(object *unstructured.Unstructured, object
|
|||
}
|
||||
}()
|
||||
|
||||
if err := d.ClaimPolicyForObject(object, policy.Namespace, policy.Name, string(policy.UID)); err != nil {
|
||||
policyID, err := d.ClaimPolicyForObject(object, policy)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to claim policy(%s) for object: %s", policy.Name, object)
|
||||
return err
|
||||
}
|
||||
|
||||
policyLabels := map[string]string{
|
||||
policyv1alpha1.PropagationPolicyNamespaceLabel: policy.GetNamespace(),
|
||||
policyv1alpha1.PropagationPolicyNameLabel: policy.GetName(),
|
||||
policyv1alpha1.PropagationPolicyUIDLabel: string(policy.UID),
|
||||
policyv1alpha1.PropagationPolicyNamespaceLabel: policy.GetNamespace(),
|
||||
policyv1alpha1.PropagationPolicyNameLabel: policy.GetName(),
|
||||
policyv1alpha1.PropagationPolicyPermanentIDLabel: policyID,
|
||||
}
|
||||
policyAnnotations := map[string]string{
|
||||
policyv1alpha1.PropagationPolicyNamespaceAnnotation: policy.GetNamespace(),
|
||||
|
@ -440,6 +442,14 @@ func (d *ResourceDetector) ApplyPolicy(object *unstructured.Unstructured, object
|
|||
return fmt.Errorf("failed to update binding due to different owner reference UID, will " +
|
||||
"try again later after binding is garbage collected, see https://github.com/karmada-io/karmada/issues/2090")
|
||||
}
|
||||
|
||||
// TODO: Delete following two lines in release-1.9
|
||||
delete(bindingCopy.Labels, workv1alpha2.ResourceBindingUIDLabel)
|
||||
delete(bindingCopy.Labels, policyv1alpha1.PropagationPolicyUIDLabel)
|
||||
if util.GetLabelValue(bindingCopy.Labels, workv1alpha2.ResourceBindingPermanentIDLabel) == "" {
|
||||
bindingCopy.Labels = util.DedupeAndMergeLabels(bindingCopy.Labels,
|
||||
map[string]string{workv1alpha2.ResourceBindingPermanentIDLabel: uuid.New().String()})
|
||||
}
|
||||
// Just update necessary fields, especially avoid modifying Spec.Clusters which is scheduling result, if already exists.
|
||||
bindingCopy.Annotations = util.DedupeAndMergeAnnotations(bindingCopy.Annotations, binding.Annotations)
|
||||
bindingCopy.Labels = util.DedupeAndMergeLabels(bindingCopy.Labels, binding.Labels)
|
||||
|
@ -492,14 +502,15 @@ func (d *ResourceDetector) ApplyClusterPolicy(object *unstructured.Unstructured,
|
|||
}
|
||||
}()
|
||||
|
||||
if err := d.ClaimClusterPolicyForObject(object, policy.Name, string(policy.UID)); err != nil {
|
||||
policyID, err := d.ClaimClusterPolicyForObject(object, policy)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to claim cluster policy(%s) for object: %s", policy.Name, object)
|
||||
return err
|
||||
}
|
||||
|
||||
policyLabels := map[string]string{
|
||||
policyv1alpha1.ClusterPropagationPolicyLabel: policy.GetName(),
|
||||
policyv1alpha1.ClusterPropagationPolicyUIDLabel: string(policy.UID),
|
||||
policyv1alpha1.ClusterPropagationPolicyLabel: policy.GetName(),
|
||||
policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: policyID,
|
||||
}
|
||||
policyAnnotations := map[string]string{
|
||||
policyv1alpha1.ClusterPropagationPolicyAnnotation: policy.GetName(),
|
||||
|
@ -523,6 +534,14 @@ func (d *ResourceDetector) ApplyClusterPolicy(object *unstructured.Unstructured,
|
|||
return fmt.Errorf("failed to update binding due to different owner reference UID, will " +
|
||||
"try again later after binding is garbage collected, see https://github.com/karmada-io/karmada/issues/2090")
|
||||
}
|
||||
|
||||
// TODO: Delete following two lines in release-1.9
|
||||
delete(bindingCopy.Labels, workv1alpha2.ResourceBindingUIDLabel)
|
||||
delete(bindingCopy.Labels, policyv1alpha1.ClusterPropagationPolicyUIDLabel)
|
||||
if util.GetLabelValue(bindingCopy.Labels, workv1alpha2.ResourceBindingPermanentIDLabel) == "" {
|
||||
bindingCopy.Labels = util.DedupeAndMergeLabels(bindingCopy.Labels,
|
||||
map[string]string{workv1alpha2.ResourceBindingPermanentIDLabel: uuid.New().String()})
|
||||
}
|
||||
// Just update necessary fields, especially avoid modifying Spec.Clusters which is scheduling result, if already exists.
|
||||
bindingCopy.Annotations = util.DedupeAndMergeAnnotations(bindingCopy.Annotations, binding.Annotations)
|
||||
bindingCopy.Labels = util.DedupeAndMergeLabels(bindingCopy.Labels, binding.Labels)
|
||||
|
@ -570,6 +589,14 @@ func (d *ResourceDetector) ApplyClusterPolicy(object *unstructured.Unstructured,
|
|||
return fmt.Errorf("failed to update binding due to different owner reference UID, will " +
|
||||
"try again later after binding is garbage collected, see https://github.com/karmada-io/karmada/issues/2090")
|
||||
}
|
||||
|
||||
// TODO: delete following two lines in release-1.9
|
||||
delete(bindingCopy.Labels, workv1alpha2.ClusterResourceBindingUIDLabel)
|
||||
delete(bindingCopy.Labels, policyv1alpha1.ClusterPropagationPolicyUIDLabel)
|
||||
if util.GetLabelValue(bindingCopy.Labels, workv1alpha2.ClusterResourceBindingPermanentIDLabel) == "" {
|
||||
bindingCopy.Labels = util.DedupeAndMergeLabels(bindingCopy.Labels,
|
||||
map[string]string{workv1alpha2.ClusterResourceBindingPermanentIDLabel: uuid.New().String()})
|
||||
}
|
||||
// Just update necessary fields, especially avoid modifying Spec.Clusters which is scheduling result, if already exists.
|
||||
bindingCopy.Annotations = util.DedupeAndMergeAnnotations(bindingCopy.Annotations, binding.Annotations)
|
||||
bindingCopy.Labels = util.DedupeAndMergeLabels(bindingCopy.Labels, binding.Labels)
|
||||
|
@ -637,51 +664,95 @@ func (d *ResourceDetector) GetUnstructuredObject(objectKey keys.ClusterWideKey)
|
|||
return unstructuredObj, nil
|
||||
}
|
||||
|
||||
func (d *ResourceDetector) getPropagationPolicyID(policy *policyv1alpha1.PropagationPolicy) (string, error) {
|
||||
id := util.GetLabelValue(policy.GetLabels(), policyv1alpha1.PropagationPolicyPermanentIDLabel)
|
||||
if id == "" {
|
||||
id = uuid.New().String()
|
||||
policy.Labels = util.DedupeAndMergeLabels(policy.Labels, map[string]string{policyv1alpha1.PropagationPolicyPermanentIDLabel: id})
|
||||
if err := d.Client.Update(context.TODO(), policy); err != nil {
|
||||
return id, err
|
||||
}
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// ClaimPolicyForObject set policy identifier which the object associated with.
|
||||
func (d *ResourceDetector) ClaimPolicyForObject(object *unstructured.Unstructured, policyNamespace, policyName, policyUID string) error {
|
||||
func (d *ResourceDetector) ClaimPolicyForObject(object *unstructured.Unstructured, policy *policyv1alpha1.PropagationPolicy) (string, error) {
|
||||
policyID, err := d.getPropagationPolicyID(policy)
|
||||
if err != nil {
|
||||
klog.Errorf("Get PropagationPolicy(%s/%s) ID error:%v", policy.Namespace, policy.Name, err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
objLabels := object.GetLabels()
|
||||
if objLabels == nil {
|
||||
objLabels = make(map[string]string)
|
||||
} else if len(objLabels) > 0 {
|
||||
// object has been claimed, don't need to claim again
|
||||
if !excludeClusterPolicy(objLabels) &&
|
||||
objLabels[policyv1alpha1.PropagationPolicyNamespaceLabel] == policyNamespace &&
|
||||
objLabels[policyv1alpha1.PropagationPolicyNameLabel] == policyName {
|
||||
return nil
|
||||
objLabels[policyv1alpha1.PropagationPolicyPermanentIDLabel] == policyID {
|
||||
return policyID, nil
|
||||
}
|
||||
}
|
||||
|
||||
objLabels[policyv1alpha1.PropagationPolicyNamespaceLabel] = policyNamespace
|
||||
objLabels[policyv1alpha1.PropagationPolicyNameLabel] = policyName
|
||||
objLabels[policyv1alpha1.PropagationPolicyUIDLabel] = policyUID
|
||||
// Delete following line when release-1.9
|
||||
delete(objLabels, policyv1alpha1.PropagationPolicyUIDLabel)
|
||||
objLabels[policyv1alpha1.PropagationPolicyNamespaceLabel] = policy.Namespace
|
||||
objLabels[policyv1alpha1.PropagationPolicyNameLabel] = policy.Name
|
||||
objLabels[policyv1alpha1.PropagationPolicyPermanentIDLabel] = policyID
|
||||
|
||||
objectAnnotations := object.GetAnnotations()
|
||||
if objectAnnotations == nil {
|
||||
objectAnnotations = make(map[string]string)
|
||||
}
|
||||
objectAnnotations[policyv1alpha1.PropagationPolicyNamespaceAnnotation] = policyNamespace
|
||||
objectAnnotations[policyv1alpha1.PropagationPolicyNameAnnotation] = policyName
|
||||
objectAnnotations[policyv1alpha1.PropagationPolicyNamespaceAnnotation] = policy.Namespace
|
||||
objectAnnotations[policyv1alpha1.PropagationPolicyNameAnnotation] = policy.Name
|
||||
|
||||
objectCopy := object.DeepCopy()
|
||||
objectCopy.SetLabels(objLabels)
|
||||
objectCopy.SetAnnotations(objectAnnotations)
|
||||
return d.Client.Update(context.TODO(), objectCopy)
|
||||
return policyID, d.Client.Update(context.TODO(), objectCopy)
|
||||
}
|
||||
|
||||
// ClaimClusterPolicyForObject set cluster identifier which the object associated with.
|
||||
func (d *ResourceDetector) ClaimClusterPolicyForObject(object *unstructured.Unstructured, policyName, policyUID string) error {
|
||||
claimedName := util.GetLabelValue(object.GetLabels(), policyv1alpha1.ClusterPropagationPolicyLabel)
|
||||
func (d *ResourceDetector) getClusterPropagationPolicyID(policy *policyv1alpha1.ClusterPropagationPolicy) (string, error) {
|
||||
id := util.GetLabelValue(policy.GetLabels(), policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel)
|
||||
if id == "" {
|
||||
id = uuid.New().String()
|
||||
policy.Labels = util.DedupeAndMergeLabels(policy.Labels, map[string]string{policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: id})
|
||||
if err := d.Client.Update(context.TODO(), policy); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// ClaimClusterPolicyForObject set cluster identifier which the object associated with
|
||||
func (d *ResourceDetector) ClaimClusterPolicyForObject(object *unstructured.Unstructured, policy *policyv1alpha1.ClusterPropagationPolicy) (string, error) {
|
||||
policyID, err := d.getClusterPropagationPolicyID(policy)
|
||||
if err != nil {
|
||||
klog.Errorf("Get ClusterPropagationPolicy(%s) ID error:%v", policy.Name, err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
claimedID := util.GetLabelValue(object.GetLabels(), policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel)
|
||||
// object has been claimed, don't need to claim again
|
||||
if claimedName == policyName {
|
||||
return nil
|
||||
if claimedID == policyID {
|
||||
return policyID, nil
|
||||
}
|
||||
|
||||
objectCopy := object.DeepCopy()
|
||||
util.MergeLabel(objectCopy, policyv1alpha1.ClusterPropagationPolicyLabel, policyName)
|
||||
util.MergeLabel(objectCopy, policyv1alpha1.ClusterPropagationPolicyUIDLabel, policyUID)
|
||||
// TODO: delete following 3 lines in release-1.9
|
||||
labels := objectCopy.GetLabels()
|
||||
delete(labels, policyv1alpha1.ClusterPropagationPolicyUIDLabel)
|
||||
objectCopy.SetLabels(labels)
|
||||
|
||||
util.MergeAnnotation(objectCopy, policyv1alpha1.ClusterPropagationPolicyAnnotation, policyName)
|
||||
return d.Client.Update(context.TODO(), objectCopy)
|
||||
util.MergeLabel(objectCopy, policyv1alpha1.ClusterPropagationPolicyLabel, policy.Name)
|
||||
util.MergeLabel(objectCopy, policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel, policyID)
|
||||
|
||||
util.MergeAnnotation(objectCopy, policyv1alpha1.ClusterPropagationPolicyAnnotation, policy.Name)
|
||||
return policyID, d.Client.Update(context.TODO(), objectCopy)
|
||||
}
|
||||
|
||||
// BuildResourceBinding builds a desired ResourceBinding for object.
|
||||
|
|
|
@ -135,7 +135,7 @@ func (d *ResourceDetector) preemptPropagationPolicy(resourceTemplate *unstructur
|
|||
"Propagation policy(%s/%s) preempted propagation policy(%s/%s) successfully", policy.Namespace, policy.Name, claimedPolicyNamespace, claimedPolicyName)
|
||||
}()
|
||||
|
||||
if err = d.ClaimPolicyForObject(resourceTemplate, policy.Namespace, policy.Name, string(policy.UID)); err != nil {
|
||||
if _, err = d.ClaimPolicyForObject(resourceTemplate, policy); err != nil {
|
||||
klog.Errorf("Failed to claim new propagation policy(%s/%s) on resource template(%s, kind=%s, %s): %v.", policy.Namespace, policy.Name,
|
||||
resourceTemplate.GetAPIVersion(), resourceTemplate.GetKind(), names.NamespacedKey(resourceTemplate.GetNamespace(), resourceTemplate.GetName()), err)
|
||||
return err
|
||||
|
@ -163,7 +163,7 @@ func (d *ResourceDetector) preemptClusterPropagationPolicyDirectly(resourceTempl
|
|||
"Propagation policy(%s/%s) preempted cluster propagation policy(%s) successfully", policy.Namespace, policy.Name, claimedPolicyName)
|
||||
}()
|
||||
|
||||
if err = d.ClaimPolicyForObject(resourceTemplate, policy.Namespace, policy.Name, string(policy.UID)); err != nil {
|
||||
if _, err = d.ClaimPolicyForObject(resourceTemplate, policy); err != nil {
|
||||
klog.Errorf("Failed to claim new propagation policy(%s/%s) on resource template(%s, kind=%s, %s) directly: %v.", policy.Namespace, policy.Name,
|
||||
resourceTemplate.GetAPIVersion(), resourceTemplate.GetKind(), names.NamespacedKey(resourceTemplate.GetNamespace(), resourceTemplate.GetName()), err)
|
||||
return err
|
||||
|
@ -213,7 +213,7 @@ func (d *ResourceDetector) preemptClusterPropagationPolicy(resourceTemplate *uns
|
|||
"Cluster propagation policy(%s) preempted cluster propagation policy(%s) successfully", policy.Name, claimedPolicyName)
|
||||
}()
|
||||
|
||||
if err = d.ClaimClusterPolicyForObject(resourceTemplate, policy.Name, string(policy.UID)); err != nil {
|
||||
if _, err = d.ClaimClusterPolicyForObject(resourceTemplate, policy); err != nil {
|
||||
klog.Errorf("Failed to claim new cluster propagation policy(%s) on resource template(%s, kind=%s, %s): %v.", policy.Name,
|
||||
resourceTemplate.GetAPIVersion(), resourceTemplate.GetKind(), names.NamespacedKey(resourceTemplate.GetNamespace(), resourceTemplate.GetName()), err)
|
||||
return err
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
@ -45,7 +46,6 @@ func CreateOrUpdateWork(client client.Client, workMeta metav1.ObjectMeta, resour
|
|||
}
|
||||
util.MergeAnnotation(workload, workv1alpha2.ResourceTemplateUIDAnnotation, string(workload.GetUID()))
|
||||
util.RecordManagedAnnotations(workload)
|
||||
util.RecordManagedLabels(workload)
|
||||
workloadJSON, err := workload.MarshalJSON()
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to marshal workload(%s/%s), Error: %v", workload.GetNamespace(), workload.GetName(), err)
|
||||
|
@ -74,9 +74,16 @@ func CreateOrUpdateWork(client client.Client, workMeta metav1.ObjectMeta, resour
|
|||
if !runtimeObject.DeletionTimestamp.IsZero() {
|
||||
return fmt.Errorf("work %s/%s is being deleted", runtimeObject.GetNamespace(), runtimeObject.GetName())
|
||||
}
|
||||
|
||||
// TODO: Delete following one line in release-1.9
|
||||
delete(runtimeObject.Labels, workv1alpha2.WorkUIDLabel)
|
||||
runtimeObject.Spec = work.Spec
|
||||
runtimeObject.Labels = work.Labels
|
||||
runtimeObject.Annotations = work.Annotations
|
||||
if util.GetLabelValue(runtimeObject.Labels, workv1alpha2.WorkPermanentIDLabel) == "" {
|
||||
runtimeObject.Labels = util.DedupeAndMergeLabels(runtimeObject.Labels, map[string]string{workv1alpha2.WorkPermanentIDLabel: uuid.New().String()})
|
||||
}
|
||||
util.RecordManagedLabels(runtimeObject)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1"
|
||||
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
||||
)
|
||||
|
||||
|
@ -58,6 +59,8 @@ func RetainLabels(desired *unstructured.Unstructured, observed *unstructured.Uns
|
|||
}
|
||||
labels[key] = value
|
||||
}
|
||||
// TODO: Delete following one line in release-1.9
|
||||
delete(labels, workv1alpha2.WorkUIDLabel)
|
||||
if len(labels) > 0 {
|
||||
desired.SetLabels(labels)
|
||||
}
|
||||
|
@ -108,18 +111,18 @@ func getDeletedLabelKeys(desired, observed *unstructured.Unstructured) sets.Set[
|
|||
|
||||
// RecordManagedLabels sets or updates the annotation(resourcetemplate.karmada.io/managed-labels)
|
||||
// to record the label keys.
|
||||
func RecordManagedLabels(object *unstructured.Unstructured) {
|
||||
annotations := object.GetAnnotations()
|
||||
func RecordManagedLabels(w *workv1alpha1.Work) {
|
||||
annotations := w.GetAnnotations()
|
||||
if annotations == nil {
|
||||
annotations = make(map[string]string, 1)
|
||||
}
|
||||
var managedKeys []string
|
||||
// record labels.
|
||||
labels := object.GetLabels()
|
||||
labels := w.GetLabels()
|
||||
for key := range labels {
|
||||
managedKeys = append(managedKeys, key)
|
||||
}
|
||||
sort.Strings(managedKeys)
|
||||
annotations[workv1alpha2.ManagedLabels] = strings.Join(managedKeys, ",")
|
||||
object.SetAnnotations(annotations)
|
||||
w.SetAnnotations(annotations)
|
||||
}
|
||||
|
|
|
@ -20,8 +20,10 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1"
|
||||
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
||||
)
|
||||
|
||||
|
@ -526,71 +528,65 @@ func TestRetainLabels(t *testing.T) {
|
|||
func TestRecordManagedLabels(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
object *unstructured.Unstructured
|
||||
expected *unstructured.Unstructured
|
||||
object *workv1alpha1.Work
|
||||
expected *workv1alpha1.Work
|
||||
}{
|
||||
{
|
||||
name: "nil label",
|
||||
object: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "demo-deployment-1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replicas": 2,
|
||||
},
|
||||
object: &workv1alpha1.Work{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "work.karmada.io/v1alpha1",
|
||||
Kind: "Work",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "demo-work-1",
|
||||
Namespace: "cluster1-ns",
|
||||
Labels: nil,
|
||||
},
|
||||
},
|
||||
expected: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "demo-deployment-1",
|
||||
"annotations": map[string]interface{}{
|
||||
workv1alpha2.ManagedLabels: "",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replicas": 2,
|
||||
expected: &workv1alpha1.Work{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "work.karmada.io/v1alpha1",
|
||||
Kind: "Work",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "demo-work-1",
|
||||
Namespace: "cluster1-ns",
|
||||
Annotations: map[string]string{
|
||||
workv1alpha2.ManagedLabels: "",
|
||||
},
|
||||
Labels: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "object has has labels",
|
||||
object: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "demo-deployment-1",
|
||||
"labels": map[string]interface{}{
|
||||
"foo": "foo",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replicas": 2,
|
||||
object: &workv1alpha1.Work{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "work.karmada.io/v1alpha1",
|
||||
Kind: "Work",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "demo-work-1",
|
||||
Namespace: "cluster1-ns",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "demo-deployment-1",
|
||||
"annotations": map[string]interface{}{
|
||||
workv1alpha2.ManagedLabels: "foo",
|
||||
},
|
||||
"labels": map[string]interface{}{
|
||||
"foo": "foo",
|
||||
},
|
||||
expected: &workv1alpha1.Work{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "work.karmada.io/v1alpha1",
|
||||
Kind: "Work",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "demo-work-1",
|
||||
Namespace: "cluster1-ns",
|
||||
Annotations: map[string]string{
|
||||
workv1alpha2.ManagedLabels: "foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replicas": 2,
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue