Merge pull request #752 from XiShanYongYe-Chang/move-work-label

Move binding's namespace/name from work's label to work's annotation
This commit is contained in:
karmada-bot 2021-10-09 17:35:50 +08:00 committed by GitHub
commit 093520bf43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 226 additions and 59 deletions

View File

@ -1,6 +1,16 @@
package v1alpha2
const (
// ResourceBindingReferenceKey is the key of ResourceBinding object.
// It is usually a unique hash value of ResourceBinding object's namespace and name, intended to be added to the Work object.
// It will be used to retrieve all Works objects that derived from a specific ResourceBinding object.
ResourceBindingReferenceKey = "resourcebinding.karmada.io/key"
// ClusterResourceBindingReferenceKey is the key of ClusterResourceBinding object.
// It is usually a unique hash value of ClusterResourceBinding object's namespace and name, intended to be added to the Work object.
// It will be used to retrieve all Works objects that derived by a specific ClusterResourceBinding object.
ClusterResourceBindingReferenceKey = "clusterresourcebinding.karmada.io/key"
// ResourceBindingNamespaceLabel is added to objects to specify associated ResourceBinding's namespace.
ResourceBindingNamespaceLabel = "resourcebinding.karmada.io/namespace"

View File

@ -8,7 +8,6 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/record"
@ -57,10 +56,8 @@ func (c *ResourceBindingController) Reconcile(ctx context.Context, req controlle
}
if !binding.DeletionTimestamp.IsZero() {
if err := helper.DeleteWorks(c.Client, labels.Set{
workv1alpha2.ResourceBindingNamespaceLabel: req.Namespace,
workv1alpha2.ResourceBindingNameLabel: req.Name,
}); err != nil {
klog.V(4).Infof("Begin to delete works owned by binding(%s).", req.NamespacedName.String())
if err := helper.DeleteWorkByRBNamespaceAndName(c.Client, req.Namespace, req.Name); err != nil {
klog.Errorf("Failed to delete works related to %s/%s: %v", binding.GetNamespace(), binding.GetName(), err)
return controllerruntime.Result{Requeue: true}, err
}
@ -147,18 +144,31 @@ func (c *ResourceBindingController) SetupWithManager(mgr controllerruntime.Manag
func(a client.Object) []reconcile.Request {
var requests []reconcile.Request
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
labels := a.GetLabels()
resourcebindingNamespace, namespaceExist := labels[workv1alpha2.ResourceBindingNamespaceLabel]
resourcebindingName, nameExist := labels[workv1alpha2.ResourceBindingNameLabel]
if !namespaceExist || !nameExist {
return nil
}
namespacesName := types.NamespacedName{
Namespace: resourcebindingNamespace,
Name: resourcebindingName,
crNamespace, namespaceExist := labels[workv1alpha2.ResourceBindingNamespaceLabel]
crName, nameExist := labels[workv1alpha2.ResourceBindingNameLabel]
if namespaceExist && nameExist {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: crNamespace,
Name: crName,
},
})
}
annotations := a.GetAnnotations()
crNamespace, namespaceExist = annotations[workv1alpha2.ResourceBindingNamespaceLabel]
crName, nameExist = annotations[workv1alpha2.ResourceBindingNameLabel]
if namespaceExist && nameExist {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: crNamespace,
Name: crName,
},
})
}
requests = append(requests, reconcile.Request{NamespacedName: namespacesName})
return requests
})

View File

@ -8,7 +8,6 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/record"
@ -57,9 +56,8 @@ func (c *ClusterResourceBindingController) Reconcile(ctx context.Context, req co
}
if !clusterResourceBinding.DeletionTimestamp.IsZero() {
if err := helper.DeleteWorks(c.Client, labels.Set{
workv1alpha2.ClusterResourceBindingLabel: req.Name,
}); err != nil {
klog.V(4).Infof("Begin to delete works owned by binding(%s).", req.NamespacedName.String())
if err := helper.DeleteWorkByCRBName(c.Client, req.Name); err != nil {
klog.Errorf("Failed to delete works related to %s: %v", clusterResourceBinding.GetName(), err)
return controllerruntime.Result{Requeue: true}, err
}
@ -141,16 +139,27 @@ func (c *ClusterResourceBindingController) SetupWithManager(mgr controllerruntim
func(a client.Object) []reconcile.Request {
var requests []reconcile.Request
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
labels := a.GetLabels()
clusterResourcebindingName, nameExist := labels[workv1alpha2.ClusterResourceBindingLabel]
if !nameExist {
return nil
}
namespacesName := types.NamespacedName{
Name: clusterResourcebindingName,
crbName, nameExist := labels[workv1alpha2.ClusterResourceBindingLabel]
if nameExist {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: crbName,
},
})
}
annotations := a.GetAnnotations()
crbName, nameExist = annotations[workv1alpha2.ClusterResourceBindingLabel]
if nameExist {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: crbName,
},
})
}
requests = append(requests, reconcile.Request{NamespacedName: namespacesName})
return requests
})

View File

@ -105,7 +105,8 @@ func ensureWork(c client.Client, workload *unstructured.Unstructured, overrideMa
}
}
annotations, err := recordAppliedOverrides(cops, ops)
annotations := mergeAnnotations(clonedWorkload, binding, scope)
annotations, err = recordAppliedOverrides(cops, ops, annotations)
if err != nil {
klog.Errorf("failed to record appliedOverrides, Error: %v", err)
return err
@ -158,22 +159,36 @@ func mergeLabel(workload *unstructured.Unstructured, workNamespace string, bindi
var workLabel = make(map[string]string)
util.MergeLabel(workload, workv1alpha2.WorkNamespaceLabel, workNamespace)
util.MergeLabel(workload, workv1alpha2.WorkNameLabel, names.GenerateWorkName(workload.GetKind(), workload.GetName(), workload.GetNamespace()))
if scope == apiextensionsv1.NamespaceScoped {
util.MergeLabel(workload, workv1alpha2.ResourceBindingNamespaceLabel, binding.GetNamespace())
util.MergeLabel(workload, workv1alpha2.ResourceBindingNameLabel, binding.GetName())
workLabel[workv1alpha2.ResourceBindingNamespaceLabel] = binding.GetNamespace()
workLabel[workv1alpha2.ResourceBindingNameLabel] = binding.GetName()
util.MergeLabel(workload, workv1alpha2.ResourceBindingReferenceKey, names.GenerateBindingReferenceKey(binding.GetNamespace(), binding.GetName()))
workLabel[workv1alpha2.ResourceBindingReferenceKey] = names.GenerateBindingReferenceKey(binding.GetNamespace(), binding.GetName())
} else {
util.MergeLabel(workload, workv1alpha2.ClusterResourceBindingLabel, binding.GetName())
workLabel[workv1alpha2.ClusterResourceBindingLabel] = binding.GetName()
util.MergeLabel(workload, workv1alpha2.ClusterResourceBindingReferenceKey, names.GenerateBindingReferenceKey("", binding.GetName()))
workLabel[workv1alpha2.ClusterResourceBindingReferenceKey] = names.GenerateBindingReferenceKey("", binding.GetName())
}
return workLabel
}
func recordAppliedOverrides(cops *overridemanager.AppliedOverrides, ops *overridemanager.AppliedOverrides) (map[string]string, error) {
func mergeAnnotations(workload *unstructured.Unstructured, binding metav1.Object, scope apiextensionsv1.ResourceScope) map[string]string {
annotations := make(map[string]string)
if scope == apiextensionsv1.NamespaceScoped {
util.MergeAnnotation(workload, workv1alpha2.ResourceBindingNamespaceLabel, binding.GetNamespace())
util.MergeAnnotation(workload, workv1alpha2.ResourceBindingNameLabel, binding.GetName())
annotations[workv1alpha2.ResourceBindingNamespaceLabel] = binding.GetNamespace()
annotations[workv1alpha2.ResourceBindingNameLabel] = binding.GetName()
} else {
util.MergeAnnotation(workload, workv1alpha2.ClusterResourceBindingLabel, binding.GetName())
annotations[workv1alpha2.ClusterResourceBindingLabel] = binding.GetName()
}
return annotations
}
func recordAppliedOverrides(cops *overridemanager.AppliedOverrides, ops *overridemanager.AppliedOverrides,
annotations map[string]string) (map[string]string, error) {
if annotations == nil {
annotations = make(map[string]string)
}
if cops != nil {
appliedBytes, err := cops.MarshalJSON()

View File

@ -6,6 +6,7 @@ import (
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -80,29 +81,51 @@ func GetBindingClusterNames(targetClusters []workv1alpha2.TargetCluster) []strin
// FindOrphanWorks retrieves all works that labeled with current binding(ResourceBinding or ClusterResourceBinding) objects,
// then pick the works that not meet current binding declaration.
func FindOrphanWorks(c client.Client, bindingNamespace, bindingName string, clusterNames []string, scope apiextensionsv1.ResourceScope) ([]workv1alpha1.Work, error) {
workList := &workv1alpha1.WorkList{}
var needJudgeWorks []workv1alpha1.Work
if scope == apiextensionsv1.NamespaceScoped {
selector := labels.SelectorFromSet(labels.Set{
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
workList, err := GetWorksByLabelSelector(c, labels.SelectorFromSet(labels.Set{
workv1alpha2.ResourceBindingNamespaceLabel: bindingNamespace,
workv1alpha2.ResourceBindingNameLabel: bindingName,
})
if err := c.List(context.TODO(), workList, &client.ListOptions{LabelSelector: selector}); err != nil {
}))
if err != nil {
klog.Errorf("Failed to get works by ResourceBinding(%s/%s): %v", bindingNamespace, bindingName, err)
return nil, err
}
needJudgeWorks = append(needJudgeWorks, workList.Items...)
workList, err = GetWorksByLabelSelector(c, labels.SelectorFromSet(labels.Set{
workv1alpha2.ResourceBindingReferenceKey: names.GenerateBindingReferenceKey(bindingNamespace, bindingName),
}))
if err != nil {
klog.Errorf("Failed to get works by ResourceBinding(%s/%s): %v", bindingNamespace, bindingName, err)
return nil, err
}
needJudgeWorks = append(needJudgeWorks, workList.Items...)
} else {
selector := labels.SelectorFromSet(labels.Set{
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
workList, err := GetWorksByLabelSelector(c, labels.SelectorFromSet(labels.Set{
workv1alpha2.ClusterResourceBindingLabel: bindingName,
})
if err := c.List(context.TODO(), workList, &client.ListOptions{LabelSelector: selector}); err != nil {
}))
if err != nil {
klog.Errorf("Failed to get works by ClusterResourceBinding(%s): %v", bindingName, err)
return nil, err
}
needJudgeWorks = append(needJudgeWorks, workList.Items...)
workList, err = GetWorksByLabelSelector(c, labels.SelectorFromSet(labels.Set{
workv1alpha2.ClusterResourceBindingReferenceKey: names.GenerateBindingReferenceKey("", bindingName),
}))
if err != nil {
klog.Errorf("Failed to get works by ClusterResourceBinding(%s): %v", bindingName, err)
return nil, err
}
needJudgeWorks = append(needJudgeWorks, workList.Items...)
}
var orphanWorks []workv1alpha1.Work
expectClusters := sets.NewString(clusterNames...)
for _, work := range workList.Items {
for _, work := range needJudgeWorks {
workTargetCluster, err := names.GetClusterName(work.GetNamespace())
if err != nil {
klog.Errorf("Failed to get cluster name which Work %s/%s belongs to. Error: %v.",
@ -173,6 +196,37 @@ func GetWorks(c client.Client, ls labels.Set) (*workv1alpha1.WorkList, error) {
return works, c.List(context.TODO(), works, listOpt)
}
// DeleteWorkByRBNamespaceAndName will delete all Work objects by ResourceBinding namespace and name.
func DeleteWorkByRBNamespaceAndName(c client.Client, namespace, name string) error {
err := DeleteWorks(c, labels.Set{
workv1alpha2.ResourceBindingReferenceKey: names.GenerateBindingReferenceKey(namespace, name),
})
if err != nil {
return err
}
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
return DeleteWorks(c, labels.Set{
workv1alpha2.ResourceBindingNamespaceLabel: namespace,
workv1alpha2.ResourceBindingNameLabel: name,
})
}
// DeleteWorkByCRBName will delete all Work objects by ClusterResourceBinding name.
func DeleteWorkByCRBName(c client.Client, name string) error {
err := DeleteWorks(c, labels.Set{
workv1alpha2.ClusterResourceBindingReferenceKey: names.GenerateBindingReferenceKey("", name),
})
if err != nil {
return err
}
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
return DeleteWorks(c, labels.Set{
workv1alpha2.ClusterResourceBindingLabel: name,
})
}
// DeleteWorks will delete all Work objects by labels.
func DeleteWorks(c client.Client, selector labels.Set) error {
workList, err := GetWorks(c, selector)
@ -185,6 +239,9 @@ func DeleteWorks(c client.Client, selector labels.Set) error {
for index, work := range workList.Items {
if err := c.Delete(context.TODO(), &workList.Items[index]); err != nil {
klog.Errorf("Failed to delete work(%s/%s): %v", work.Namespace, work.Name, err)
if apierrors.IsNotFound(err) {
continue
}
errs = append(errs, err)
}
}

View File

@ -5,6 +5,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
@ -59,3 +60,14 @@ func CreateOrUpdateWork(client client.Client, workMeta metav1.ObjectMeta, resour
return nil
}
// GetWorksByLabelSelector get WorkList by matching label selector.
func GetWorksByLabelSelector(c client.Client, selector labels.Selector) (*workv1alpha1.WorkList, error) {
workList := &workv1alpha1.WorkList{}
err := c.List(context.TODO(), workList, &client.ListOptions{LabelSelector: selector})
if err != nil {
return nil, err
}
return workList, nil
}

View File

@ -22,10 +22,33 @@ import (
// AggregateResourceBindingWorkStatus will collect all work statuses with current ResourceBinding objects,
// then aggregate status info to current ResourceBinding status.
func AggregateResourceBindingWorkStatus(c client.Client, binding *workv1alpha2.ResourceBinding, workload *unstructured.Unstructured) error {
aggregatedStatuses, err := assembleWorkStatus(c, labels.SelectorFromSet(labels.Set{
workv1alpha2.ResourceBindingNamespaceLabel: binding.Namespace,
workv1alpha2.ResourceBindingNameLabel: binding.Name,
}), workload)
var targetWorks []workv1alpha1.Work
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
workList, err := GetWorksByLabelSelector(c, labels.SelectorFromSet(
labels.Set{
workv1alpha2.ResourceBindingNamespaceLabel: binding.Namespace,
workv1alpha2.ResourceBindingNameLabel: binding.Name,
},
))
if err != nil {
klog.Errorf("Failed to get works by ResourceBinding(%s/%s): %v", binding.Namespace, binding.Name, err)
return err
}
targetWorks = append(targetWorks, workList.Items...)
workList, err = GetWorksByLabelSelector(c, labels.SelectorFromSet(
labels.Set{
workv1alpha2.ResourceBindingReferenceKey: names.GenerateBindingReferenceKey(binding.Namespace, binding.Name),
},
))
if err != nil {
klog.Errorf("Failed to get works by ResourceBinding(%s/%s): %v", binding.Namespace, binding.Name, err)
return err
}
targetWorks = append(targetWorks, workList.Items...)
aggregatedStatuses, err := assembleWorkStatus(targetWorks, workload)
if err != nil {
return err
}
@ -47,9 +70,32 @@ func AggregateResourceBindingWorkStatus(c client.Client, binding *workv1alpha2.R
// AggregateClusterResourceBindingWorkStatus will collect all work statuses with current ClusterResourceBinding objects,
// then aggregate status info to current ClusterResourceBinding status.
func AggregateClusterResourceBindingWorkStatus(c client.Client, binding *workv1alpha2.ClusterResourceBinding, workload *unstructured.Unstructured) error {
aggregatedStatuses, err := assembleWorkStatus(c, labels.SelectorFromSet(labels.Set{
workv1alpha2.ClusterResourceBindingLabel: binding.Name,
}), workload)
var targetWorks []workv1alpha1.Work
// TODO: Delete this logic in the next release to prevent incompatibility when upgrading the current release (v0.10.0).
workList, err := GetWorksByLabelSelector(c, labels.SelectorFromSet(
labels.Set{
workv1alpha2.ClusterResourceBindingLabel: binding.Name,
},
))
if err != nil {
klog.Errorf("Failed to get works by ClusterResourceBinding(%s): %v", binding.Name, err)
return err
}
targetWorks = append(targetWorks, workList.Items...)
workList, err = GetWorksByLabelSelector(c, labels.SelectorFromSet(
labels.Set{
workv1alpha2.ClusterResourceBindingReferenceKey: names.GenerateBindingReferenceKey("", binding.Name),
},
))
if err != nil {
klog.Errorf("Failed to get works by ClusterResourceBinding(%s): %v", binding.Name, err)
return err
}
targetWorks = append(targetWorks, workList.Items...)
aggregatedStatuses, err := assembleWorkStatus(targetWorks, workload)
if err != nil {
return err
}
@ -69,14 +115,9 @@ func AggregateClusterResourceBindingWorkStatus(c client.Client, binding *workv1a
}
// assemble workStatuses from workList which list by selector and match with workload.
func assembleWorkStatus(c client.Client, selector labels.Selector, workload *unstructured.Unstructured) ([]workv1alpha2.AggregatedStatusItem, error) {
workList := &workv1alpha1.WorkList{}
if err := c.List(context.TODO(), workList, &client.ListOptions{LabelSelector: selector}); err != nil {
return nil, err
}
func assembleWorkStatus(works []workv1alpha1.Work, workload *unstructured.Unstructured) ([]workv1alpha2.AggregatedStatusItem, error) {
statuses := make([]workv1alpha2.AggregatedStatusItem, 0)
for _, work := range workList.Items {
for _, work := range works {
identifierIndex, err := GetManifestIndex(work.Spec.Workload.Manifests, workload)
if err != nil {
klog.Errorf("Failed to get manifestIndex of workload in work.Spec.Workload.Manifests. Error: %v.", err)

View File

@ -58,6 +58,19 @@ func GenerateBindingName(kind, name string) string {
return strings.ToLower(name + "-" + kind)
}
// GenerateBindingReferenceKey will generate the key of binding object with the hash of its namespace and name.
func GenerateBindingReferenceKey(namespace, name string) string {
var bindingName string
if len(namespace) == 0 {
bindingName = namespace + "-" + name
} else {
bindingName = name
}
hash := fnv.New32a()
hashutil.DeepHashObject(hash, bindingName)
return rand.SafeEncodeString(fmt.Sprint(hash.Sum32()))
}
// GenerateWorkName will generate work name by its name and the hash of its namespace, kind and name.
func GenerateWorkName(kind, name, namespace string) string {
var workName string