Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move binding's namespace/name from work's label to work's annotation #752

Merged
merged 1 commit into from
Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pkg/apis/work/v1alpha2/well_known_labels.go
Original file line number Diff line number Diff line change
@@ -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"

Expand Down
36 changes: 23 additions & 13 deletions pkg/controllers/binding/binding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
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,
},
})
}
namespacesName := types.NamespacedName{
Namespace: resourcebindingNamespace,
Name: resourcebindingName,

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
})

Expand Down
29 changes: 19 additions & 10 deletions pkg/controllers/binding/cluster_resource_binding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
crbName, nameExist := labels[workv1alpha2.ClusterResourceBindingLabel]
if nameExist {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: crbName,
},
})
}
namespacesName := types.NamespacedName{
Name: clusterResourcebindingName,

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
})

Expand Down
35 changes: 25 additions & 10 deletions pkg/controllers/binding/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
73 changes: 65 additions & 8 deletions pkg/util/helper/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 != nil {
klog.Errorf("Failed to get works by ResourceBinding(%s/%s): %v", bindingNamespace, bindingName, err)
return nil, err
}
needJudgeWorks = append(needJudgeWorks, workList.Items...)

if err := c.List(context.TODO(), workList, &client.ListOptions{LabelSelector: selector}); err != nil {
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 != nil {
klog.Errorf("Failed to get works by ClusterResourceBinding(%s): %v", bindingName, err)
return nil, err
}
needJudgeWorks = append(needJudgeWorks, workList.Items...)

if err := c.List(context.TODO(), workList, &client.ListOptions{LabelSelector: selector}); err != nil {
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.",
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/util/helper/work.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Loading