karmada/pkg/controllers/status/cluster_condition_cache.go

86 lines
2.7 KiB
Go

package status
import (
"sync"
"time"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
)
type clusterData struct {
// readyCondition is the last observed ready condition of the cluster.
readyCondition metav1.ConditionStatus
// thresholdStartTime is the time that the ready condition changed.
thresholdStartTime time.Time
}
type clusterConditionStore struct {
clusterDataMap sync.Map
// successThreshold is the duration of successes for the cluster to be considered healthy after recovery.
successThreshold time.Duration
// failureThreshold is the duration of failure for the cluster to be considered unhealthy.
failureThreshold time.Duration
}
func (c *clusterConditionStore) thresholdAdjustedReadyCondition(cluster *clusterv1alpha1.Cluster, observedReadyCondition *metav1.Condition) *metav1.Condition {
saved := c.get(cluster.Name)
if saved == nil {
// the cluster is just joined
c.update(cluster.Name, &clusterData{
readyCondition: observedReadyCondition.Status,
})
return observedReadyCondition
}
curReadyCondition := meta.FindStatusCondition(cluster.Status.Conditions, clusterv1alpha1.ClusterConditionReady)
if curReadyCondition == nil {
return observedReadyCondition
}
now := time.Now()
if saved.readyCondition != observedReadyCondition.Status {
// ready condition status changed, record the threshold start time
saved = &clusterData{
readyCondition: observedReadyCondition.Status,
thresholdStartTime: now,
}
c.update(cluster.Name, saved)
}
var threshold time.Duration
if observedReadyCondition.Status == metav1.ConditionTrue {
threshold = c.successThreshold
} else {
threshold = c.failureThreshold
}
// we only care about true/not true
// for unknown->false, just return the observed ready condition
if ((observedReadyCondition.Status == metav1.ConditionTrue && curReadyCondition.Status != metav1.ConditionTrue) ||
(observedReadyCondition.Status != metav1.ConditionTrue && curReadyCondition.Status == metav1.ConditionTrue)) &&
now.Before(saved.thresholdStartTime.Add(threshold)) {
// retain old status until threshold exceeded to avoid network unstable problems.
return curReadyCondition
}
return observedReadyCondition
}
func (c *clusterConditionStore) get(cluster string) *clusterData {
condition, ok := c.clusterDataMap.Load(cluster)
if !ok {
return nil
}
return condition.(*clusterData)
}
func (c *clusterConditionStore) update(cluster string, data *clusterData) {
// ready condition status changed, record the threshold start time
c.clusterDataMap.Store(cluster, data)
}
func (c *clusterConditionStore) delete(cluster string) {
c.clusterDataMap.Delete(cluster)
}