Files
kubesphere/pkg/controller/clusterlabel/clusterlabel_controller.go
2025-04-30 15:53:51 +08:00

130 lines
3.6 KiB
Go

/*
* Copyright 2024 the KubeSphere Authors.
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package clusterlabel
import (
"context"
"fmt"
"strings"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/predicate"
clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1"
kscontroller "kubesphere.io/kubesphere/pkg/controller"
)
// Reconciler is a reconciler for the Label object.
type Reconciler struct {
client.Client
}
func (r *Reconciler) Name() string {
return "clusterlabel"
}
func (r *Reconciler) Enabled(clusterRole string) bool {
return strings.EqualFold(clusterRole, string(clusterv1alpha1.ClusterRoleHost))
}
// Reconcile reconciles the Label object, sync label to the individual Cluster CRs.
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
label := &clusterv1alpha1.Label{}
if err := r.Get(ctx, req.NamespacedName, label); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
if label.DeletionTimestamp != nil {
return ctrl.Result{}, r.deleteLabel(ctx, label)
}
if len(label.Finalizers) == 0 {
label.Finalizers = []string{clusterv1alpha1.LabelFinalizer}
if err := r.Update(ctx, label); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{Requeue: true}, nil
}
return ctrl.Result{}, r.syncLabelToClusters(ctx, label)
}
func (r *Reconciler) syncLabelToClusters(ctx context.Context, label *clusterv1alpha1.Label) error {
klog.V(4).Infof("sync label %s[%s/%v] to clusters: %v", label.Name, label.Spec.Key, label.Spec.Value, label.Spec.Clusters)
clusterSets := sets.NewString(label.Spec.Clusters...)
for name := range clusterSets {
cluster := &clusterv1alpha1.Cluster{}
if err := r.Get(ctx, client.ObjectKey{Name: name}, cluster); err != nil {
if errors.IsNotFound(err) {
clusterSets.Delete(name)
continue
} else {
return err
}
}
if cluster.Labels == nil {
cluster.Labels = make(map[string]string)
}
if _, ok := cluster.Labels[fmt.Sprintf(clusterv1alpha1.ClusterLabelFormat, label.Name)]; ok {
continue
}
cluster.Labels[fmt.Sprintf(clusterv1alpha1.ClusterLabelFormat, label.Name)] = ""
if err := r.Update(ctx, cluster); err != nil {
return err
}
}
clusters := clusterSets.List()
// some clusters have been deleted and this list needs to be updated
if len(clusters) != len(label.Spec.Clusters) {
label.Spec.Clusters = clusters
return r.Update(ctx, label)
}
return nil
}
func (r *Reconciler) deleteLabel(ctx context.Context, label *clusterv1alpha1.Label) error {
klog.V(4).Infof("deleting label %s, removing cluster %v related label", label.Name, label.Spec.Clusters)
for _, name := range label.Spec.Clusters {
cluster := &clusterv1alpha1.Cluster{}
if err := r.Get(ctx, client.ObjectKey{Name: name}, cluster); err != nil {
if errors.IsNotFound(err) {
continue
} else {
return err
}
}
delete(cluster.Labels, fmt.Sprintf(clusterv1alpha1.ClusterLabelFormat, label.Name))
if err := r.Update(ctx, cluster); err != nil {
return err
}
}
label.Finalizers = nil
return r.Update(ctx, label)
}
func (r *Reconciler) SetupWithManager(mgr *kscontroller.Manager) error {
r.Client = mgr.GetClient()
return builder.
ControllerManagedBy(mgr).
For(
&clusterv1alpha1.Label{},
builder.WithPredicates(
predicate.ResourceVersionChangedPredicate{},
),
).
Named(r.Name()).
Complete(r)
}