120 lines
3.6 KiB
Go
120 lines
3.6 KiB
Go
/*
|
|
Copyright 2023 The Karmada Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package applicationfailover
|
|
|
|
import (
|
|
"sync"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
|
|
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
|
)
|
|
|
|
type workloadUnhealthyMap struct {
|
|
sync.RWMutex
|
|
// key is the NamespacedName of the binding
|
|
// value is also a map. Its key is the cluster where the unhealthy workload resides.
|
|
// Its value is the time when the unhealthy state was first observed.
|
|
workloadUnhealthy map[types.NamespacedName]map[string]metav1.Time
|
|
}
|
|
|
|
func newWorkloadUnhealthyMap() *workloadUnhealthyMap {
|
|
return &workloadUnhealthyMap{
|
|
workloadUnhealthy: make(map[types.NamespacedName]map[string]metav1.Time),
|
|
}
|
|
}
|
|
|
|
func (m *workloadUnhealthyMap) delete(key types.NamespacedName) {
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
delete(m.workloadUnhealthy, key)
|
|
}
|
|
|
|
func (m *workloadUnhealthyMap) hasWorkloadBeenUnhealthy(key types.NamespacedName, cluster string) bool {
|
|
m.RLock()
|
|
defer m.RUnlock()
|
|
|
|
unhealthyClusters := m.workloadUnhealthy[key]
|
|
if unhealthyClusters == nil {
|
|
return false
|
|
}
|
|
|
|
_, exist := unhealthyClusters[cluster]
|
|
return exist
|
|
}
|
|
|
|
func (m *workloadUnhealthyMap) setTimeStamp(key types.NamespacedName, cluster string) {
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
unhealthyClusters := m.workloadUnhealthy[key]
|
|
if unhealthyClusters == nil {
|
|
unhealthyClusters = make(map[string]metav1.Time)
|
|
}
|
|
|
|
unhealthyClusters[cluster] = metav1.Now()
|
|
m.workloadUnhealthy[key] = unhealthyClusters
|
|
}
|
|
|
|
func (m *workloadUnhealthyMap) getTimeStamp(key types.NamespacedName, cluster string) metav1.Time {
|
|
m.RLock()
|
|
defer m.RUnlock()
|
|
|
|
unhealthyClusters := m.workloadUnhealthy[key]
|
|
return unhealthyClusters[cluster]
|
|
}
|
|
|
|
func (m *workloadUnhealthyMap) deleteIrrelevantClusters(key types.NamespacedName, allClusters sets.Set[string], healthyClusters []string) {
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
unhealthyClusters := m.workloadUnhealthy[key]
|
|
if unhealthyClusters == nil {
|
|
return
|
|
}
|
|
for cluster := range unhealthyClusters {
|
|
if !allClusters.Has(cluster) {
|
|
delete(unhealthyClusters, cluster)
|
|
}
|
|
}
|
|
for _, cluster := range healthyClusters {
|
|
delete(unhealthyClusters, cluster)
|
|
}
|
|
|
|
m.workloadUnhealthy[key] = unhealthyClusters
|
|
}
|
|
|
|
// distinguishUnhealthyClustersWithOthers distinguishes clusters which is in the unHealthy state(not in the process of eviction) with others.
|
|
func distinguishUnhealthyClustersWithOthers(aggregatedStatusItems []workv1alpha2.AggregatedStatusItem, resourceBindingSpec workv1alpha2.ResourceBindingSpec) ([]string, []string) {
|
|
var unhealthyClusters, others []string
|
|
for _, aggregatedStatusItem := range aggregatedStatusItems {
|
|
cluster := aggregatedStatusItem.ClusterName
|
|
|
|
if aggregatedStatusItem.Health == workv1alpha2.ResourceUnhealthy && !resourceBindingSpec.ClusterInGracefulEvictionTasks(cluster) {
|
|
unhealthyClusters = append(unhealthyClusters, cluster)
|
|
}
|
|
|
|
if aggregatedStatusItem.Health == workv1alpha2.ResourceHealthy || aggregatedStatusItem.Health == workv1alpha2.ResourceUnknown {
|
|
others = append(others, cluster)
|
|
}
|
|
}
|
|
|
|
return unhealthyClusters, others
|
|
}
|