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