* Copyright (c) 2024 Huawei Technologies Co., Ltd.
* openFuyao is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package controller
import (
"context"
"time"
"github.com/karmada-io/karmada/pkg/generated/clientset/versioned"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/util/retry"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
"openfuyao.com/multi-cluster-service/api/v1beta1"
"openfuyao.com/multi-cluster-service/pkg/cluster"
"openfuyao.com/multi-cluster-service/pkg/zlog"
)
type ClusterReconciler struct {
client.Client
Scheme *runtime.Scheme
KarmadaClient *versioned.Clientset
}
const (
defaultOpenFuyaoFinalizers = "finalizers.multicluster.openfuyao.com"
defaultUpdateFrequency = 30 * time.Second
)
func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
clusterObj := &v1beta1.Cluster{}
if err := r.Get(ctx, req.NamespacedName, clusterObj); err != nil {
if errors.IsNotFound(err) {
zlog.Warnf("NotFound cluster object to reconcile.")
return ctrl.Result{}, client.IgnoreNotFound(err)
}
zlog.LogErrorf("Error Retrieving cluster object : %v", err)
return ctrl.Result{}, err
}
return r.syncClusterStatus(ctx, clusterObj)
}
func (r *ClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&v1beta1.Cluster{}).
Complete(r)
}
func (r *ClusterReconciler) syncClusterStatus(ctx context.Context, obj *v1beta1.Cluster) (ctrl.Result, error) {
currentClusterStatus := *obj.Status.DeepCopy()
cpuAndMemoryUsage, currentCondition, err := cluster.RetrieveClusterStatus(obj.Name, r.KarmadaClient)
if err != nil {
if err.Error() == "cluster object is not ready" {
return ctrl.Result{}, err
}
zlog.LogErrorf("Error Retrieving cluster object resources: %v", err)
return ctrl.Result{}, err
}
zlog.LogInfof("cluster %s is ready, synchronization of object status can proceed.\n", obj.Name)
currentClusterStatus.ResourceList.AllocatableCPU = cpuAndMemoryUsage.AllocatableCPU
currentClusterStatus.ResourceList.AllocatableMemory = cpuAndMemoryUsage.AllocatableMemory
currentClusterStatus.ResourceList.AllocatedCPU = cpuAndMemoryUsage.AllocatedCPU
currentClusterStatus.ResourceList.AllocatedMemory = cpuAndMemoryUsage.AllocatedMemory
currentClusterStatus.Condition = nil
currentClusterStatus.Condition = currentCondition
return r.updateStatus(ctx, obj, currentClusterStatus)
}
func (r *ClusterReconciler) updateStatus(ctx context.Context, obj *v1beta1.Cluster,
newStatus v1beta1.ClusterStatus) (ctrl.Result, error) {
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
clusterObj := v1beta1.Cluster{}
if err := r.Get(ctx, client.ObjectKeyFromObject(obj), &clusterObj); err != nil {
zlog.LogErrorf("Error Retrieving cluster object : %v", err)
return err
}
clusterObj.Status.Condition = nil
clusterObj.Status.Condition = newStatus.Condition
clusterObj.Status.ResourceList.AllocatableCPU = newStatus.ResourceList.AllocatableCPU
clusterObj.Status.ResourceList.AllocatableMemory = newStatus.ResourceList.AllocatableMemory
clusterObj.Status.ResourceList.AllocatedCPU = newStatus.ResourceList.AllocatedCPU
clusterObj.Status.ResourceList.AllocatedMemory = newStatus.ResourceList.AllocatedMemory
return r.Status().Update(ctx, &clusterObj)
})
if err != nil {
zlog.LogErrorf("Error Updating cluster status : %v", err)
return ctrl.Result{}, nil
}
return ctrl.Result{RequeueAfter: defaultUpdateFrequency}, nil
}