247 lines
7.8 KiB
Go
247 lines
7.8 KiB
Go
package spreadconstraint
|
|
|
|
import (
|
|
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
|
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
|
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
|
"github.com/karmada-io/karmada/pkg/scheduler/framework"
|
|
)
|
|
|
|
// GroupClustersInfo indicate the cluster global view
|
|
type GroupClustersInfo struct {
|
|
Providers map[string]ProviderInfo
|
|
Regions map[string]RegionInfo
|
|
Zones map[string]ZoneInfo
|
|
|
|
// Clusters from global view, sorted by cluster.Score descending.
|
|
Clusters []ClusterDetailInfo
|
|
|
|
calAvailableReplicasFunc func(clusters []*clusterv1alpha1.Cluster, spec *workv1alpha2.ResourceBindingSpec) []workv1alpha2.TargetCluster
|
|
}
|
|
|
|
// ProviderInfo indicate the provider information
|
|
type ProviderInfo struct {
|
|
Name string
|
|
Score int64 // the highest score in all clusters of the provider
|
|
AvailableReplicas int64
|
|
|
|
// Regions under this provider
|
|
Regions map[string]struct{}
|
|
// Zones under this provider
|
|
Zones map[string]struct{}
|
|
// Clusters under this provider, sorted by cluster.Score descending.
|
|
Clusters []ClusterDetailInfo
|
|
}
|
|
|
|
// RegionInfo indicate the region information
|
|
type RegionInfo struct {
|
|
Name string
|
|
Score int64 // the highest score in all clusters of the region
|
|
AvailableReplicas int64
|
|
|
|
// Zones under this provider
|
|
Zones map[string]struct{}
|
|
// Clusters under this region, sorted by cluster.Score descending.
|
|
Clusters []ClusterDetailInfo
|
|
}
|
|
|
|
// ZoneInfo indicate the zone information
|
|
type ZoneInfo struct {
|
|
Name string
|
|
Score int64 // the highest score in all clusters of the zone
|
|
AvailableReplicas int64
|
|
|
|
// Clusters under this zone, sorted by cluster.Score descending.
|
|
Clusters []ClusterDetailInfo
|
|
}
|
|
|
|
// ClusterDetailInfo indicate the cluster information
|
|
type ClusterDetailInfo struct {
|
|
Name string
|
|
Score int64
|
|
AvailableReplicas int64
|
|
|
|
Cluster *clusterv1alpha1.Cluster
|
|
}
|
|
|
|
// GroupClustersWithScore groups cluster base provider/region/zone/cluster
|
|
func GroupClustersWithScore(
|
|
clustersScore framework.ClusterScoreList,
|
|
placement *policyv1alpha1.Placement,
|
|
spec *workv1alpha2.ResourceBindingSpec,
|
|
calAvailableReplicasFunc func(clusters []*clusterv1alpha1.Cluster, spec *workv1alpha2.ResourceBindingSpec) []workv1alpha2.TargetCluster,
|
|
) *GroupClustersInfo {
|
|
if isTopologyIgnored(placement) {
|
|
return groupClustersIngoreTopology(clustersScore, spec, calAvailableReplicasFunc)
|
|
}
|
|
|
|
return groupClustersBasedTopology(clustersScore, spec, placement.SpreadConstraints, calAvailableReplicasFunc)
|
|
}
|
|
|
|
func groupClustersBasedTopology(
|
|
clustersScore framework.ClusterScoreList,
|
|
rbSpec *workv1alpha2.ResourceBindingSpec,
|
|
spreadConstraints []policyv1alpha1.SpreadConstraint,
|
|
calAvailableReplicasFunc func(clusters []*clusterv1alpha1.Cluster, spec *workv1alpha2.ResourceBindingSpec) []workv1alpha2.TargetCluster,
|
|
) *GroupClustersInfo {
|
|
groupClustersInfo := &GroupClustersInfo{
|
|
Providers: make(map[string]ProviderInfo),
|
|
Regions: make(map[string]RegionInfo),
|
|
Zones: make(map[string]ZoneInfo),
|
|
}
|
|
groupClustersInfo.calAvailableReplicasFunc = calAvailableReplicasFunc
|
|
groupClustersInfo.generateClustersInfo(clustersScore, rbSpec)
|
|
groupClustersInfo.generateZoneInfo(spreadConstraints)
|
|
groupClustersInfo.generateRegionInfo(spreadConstraints)
|
|
groupClustersInfo.generateProviderInfo(spreadConstraints)
|
|
|
|
return groupClustersInfo
|
|
}
|
|
|
|
func groupClustersIngoreTopology(
|
|
clustersScore framework.ClusterScoreList,
|
|
rbSpec *workv1alpha2.ResourceBindingSpec,
|
|
calAvailableReplicasFunc func(clusters []*clusterv1alpha1.Cluster, spec *workv1alpha2.ResourceBindingSpec) []workv1alpha2.TargetCluster,
|
|
) *GroupClustersInfo {
|
|
groupClustersInfo := &GroupClustersInfo{}
|
|
groupClustersInfo.calAvailableReplicasFunc = calAvailableReplicasFunc
|
|
groupClustersInfo.generateClustersInfo(clustersScore, rbSpec)
|
|
|
|
return groupClustersInfo
|
|
}
|
|
|
|
func (info *GroupClustersInfo) generateClustersInfo(clustersScore framework.ClusterScoreList, rbSpec *workv1alpha2.ResourceBindingSpec) {
|
|
var clusters []*clusterv1alpha1.Cluster
|
|
for _, clusterScore := range clustersScore {
|
|
clusterInfo := ClusterDetailInfo{}
|
|
clusterInfo.Name = clusterScore.Cluster.Name
|
|
clusterInfo.Score = clusterScore.Score
|
|
clusterInfo.Cluster = clusterScore.Cluster
|
|
info.Clusters = append(info.Clusters, clusterInfo)
|
|
clusters = append(clusters, clusterScore.Cluster)
|
|
}
|
|
|
|
clustersReplicas := info.calAvailableReplicasFunc(clusters, rbSpec)
|
|
for i, clustersReplica := range clustersReplicas {
|
|
info.Clusters[i].AvailableReplicas = int64(clustersReplica.Replicas)
|
|
info.Clusters[i].AvailableReplicas += int64(rbSpec.AssignedReplicasForCluster(clustersReplica.Name))
|
|
}
|
|
|
|
sortClusters(info.Clusters)
|
|
}
|
|
|
|
func (info *GroupClustersInfo) generateZoneInfo(spreadConstraints []policyv1alpha1.SpreadConstraint) {
|
|
if !IsSpreadConstraintExisted(spreadConstraints, policyv1alpha1.SpreadByFieldZone) {
|
|
return
|
|
}
|
|
|
|
for _, clusterInfo := range info.Clusters {
|
|
zones := clusterInfo.Cluster.Spec.Zones
|
|
if len(zones) == 0 {
|
|
continue
|
|
}
|
|
|
|
for _, zone := range zones {
|
|
zoneInfo, ok := info.Zones[zone]
|
|
if !ok {
|
|
zoneInfo = ZoneInfo{
|
|
Name: zone,
|
|
Clusters: make([]ClusterDetailInfo, 0),
|
|
}
|
|
}
|
|
zoneInfo.Clusters = append(zoneInfo.Clusters, clusterInfo)
|
|
zoneInfo.AvailableReplicas += clusterInfo.AvailableReplicas
|
|
info.Zones[zone] = zoneInfo
|
|
}
|
|
}
|
|
|
|
for zone, zoneInfo := range info.Zones {
|
|
zoneInfo.Score = zoneInfo.Clusters[0].Score
|
|
info.Zones[zone] = zoneInfo
|
|
}
|
|
}
|
|
|
|
func (info *GroupClustersInfo) generateRegionInfo(spreadConstraints []policyv1alpha1.SpreadConstraint) {
|
|
if !IsSpreadConstraintExisted(spreadConstraints, policyv1alpha1.SpreadByFieldRegion) {
|
|
return
|
|
}
|
|
|
|
for _, clusterInfo := range info.Clusters {
|
|
region := clusterInfo.Cluster.Spec.Region
|
|
if region == "" {
|
|
continue
|
|
}
|
|
|
|
regionInfo, ok := info.Regions[region]
|
|
if !ok {
|
|
regionInfo = RegionInfo{
|
|
Name: region,
|
|
Zones: make(map[string]struct{}),
|
|
Clusters: make([]ClusterDetailInfo, 0),
|
|
}
|
|
}
|
|
|
|
if clusterInfo.Cluster.Spec.Zone != "" {
|
|
regionInfo.Zones[clusterInfo.Cluster.Spec.Zone] = struct{}{}
|
|
}
|
|
regionInfo.Clusters = append(regionInfo.Clusters, clusterInfo)
|
|
regionInfo.AvailableReplicas += clusterInfo.AvailableReplicas
|
|
info.Regions[region] = regionInfo
|
|
}
|
|
|
|
for region, regionInfo := range info.Regions {
|
|
regionInfo.Score = regionInfo.Clusters[0].Score
|
|
info.Regions[region] = regionInfo
|
|
}
|
|
}
|
|
|
|
func (info *GroupClustersInfo) generateProviderInfo(spreadConstraints []policyv1alpha1.SpreadConstraint) {
|
|
if !IsSpreadConstraintExisted(spreadConstraints, policyv1alpha1.SpreadByFieldProvider) {
|
|
return
|
|
}
|
|
|
|
for _, clusterInfo := range info.Clusters {
|
|
provider := clusterInfo.Cluster.Spec.Provider
|
|
if provider == "" {
|
|
continue
|
|
}
|
|
|
|
providerInfo, ok := info.Providers[provider]
|
|
if !ok {
|
|
providerInfo = ProviderInfo{
|
|
Name: provider,
|
|
Regions: make(map[string]struct{}),
|
|
Zones: make(map[string]struct{}),
|
|
Clusters: make([]ClusterDetailInfo, 0),
|
|
}
|
|
}
|
|
|
|
if clusterInfo.Cluster.Spec.Zone != "" {
|
|
providerInfo.Zones[clusterInfo.Cluster.Spec.Zone] = struct{}{}
|
|
}
|
|
|
|
if clusterInfo.Cluster.Spec.Region != "" {
|
|
providerInfo.Regions[clusterInfo.Cluster.Spec.Region] = struct{}{}
|
|
}
|
|
|
|
providerInfo.Clusters = append(providerInfo.Clusters, clusterInfo)
|
|
providerInfo.AvailableReplicas += clusterInfo.AvailableReplicas
|
|
info.Providers[provider] = providerInfo
|
|
}
|
|
|
|
for provider, providerInfo := range info.Providers {
|
|
providerInfo.Score = providerInfo.Clusters[0].Score
|
|
info.Providers[provider] = providerInfo
|
|
}
|
|
}
|
|
|
|
func isTopologyIgnored(placement *policyv1alpha1.Placement) bool {
|
|
spreadConstraints := placement.SpreadConstraints
|
|
|
|
if len(spreadConstraints) == 0 || (len(spreadConstraints) == 1 && spreadConstraints[0].SpreadByField == policyv1alpha1.SpreadByFieldCluster) {
|
|
return true
|
|
}
|
|
|
|
return shouldIgnoreSpreadConstraint(placement)
|
|
}
|