@@ -68,10 +68,13 @@ func (se *SchedulerEstimator) MaxAvailableReplicas(
6868}
6969
7070// MaxAvailableComponentSets returns the maximum number of complete multi-component sets (in terms of replicas) that each cluster can host.
71- func (se * SchedulerEstimator ) MaxAvailableComponentSets (_ context.Context , _ ComponentSetEstimationRequest ) ([]ComponentSetEstimationResponse , error ) {
72- // Dummy implementation: return nothing for now
73- // TODO: Implement as part of #6734
74- return nil , nil
71+ func (se * SchedulerEstimator ) MaxAvailableComponentSets (
72+ parentCtx context.Context ,
73+ req ComponentSetEstimationRequest ,
74+ ) ([]ComponentSetEstimationResponse , error ) {
75+ return getClusterComponentSetsConcurrently (parentCtx , req .Clusters , se .timeout , func (ctx context.Context , cluster string ) (int32 , error ) {
76+ return se .maxAvailableComponentSets (ctx , cluster , req .Namespace , req .Components )
77+ })
7578}
7679
7780// GetUnschedulableReplicas gets the unschedulable replicas which belong to a specified workload by calling karmada-scheduler-estimator.
@@ -86,6 +89,62 @@ func (se *SchedulerEstimator) GetUnschedulableReplicas(
8689 })
8790}
8891
92+ func (se * SchedulerEstimator ) maxAvailableComponentSets (
93+ ctx context.Context ,
94+ cluster string ,
95+ namespace string ,
96+ components []workv1alpha2.Component ,
97+ ) (int32 , error ) {
98+ client , err := se .cache .GetClient (cluster )
99+ if err != nil {
100+ return 0 , err
101+ }
102+
103+ pbReq := & pb.MaxAvailableComponentSetsRequest {
104+ Cluster : cluster ,
105+ Components : make ([]pb.Component , 0 , len (components )),
106+ }
107+
108+ for _ , comp := range components {
109+ // Deep-copy so that pointer is not shared between goroutines
110+ var cr * workv1alpha2.ComponentReplicaRequirements
111+ if comp .ReplicaRequirements != nil {
112+ cr = comp .ReplicaRequirements .DeepCopy ()
113+ }
114+
115+ pbReq .Components = append (pbReq .Components , pb.Component {
116+ Name : comp .Name ,
117+ Replicas : comp .Replicas ,
118+ ReplicaRequirements : toPBReplicaRequirements (cr , namespace ),
119+ })
120+ }
121+
122+ res , err := client .MaxAvailableComponentSets (ctx , pbReq )
123+ if err != nil {
124+ return 0 , fmt .Errorf ("gRPC request cluster(%s) estimator error when calling MaxAvailableComponentSets: %v" , cluster , err )
125+ }
126+ return res .MaxSets , nil
127+ }
128+
129+ // toPBReplicaRequirements converts the API ComponentReplicaRequirements to the pb.ReplicaRequirements value.
130+ func toPBReplicaRequirements (cr * workv1alpha2.ComponentReplicaRequirements , namespace string ) pb.ReplicaRequirements {
131+ var out pb.ReplicaRequirements
132+ out .Namespace = namespace
133+ if cr == nil {
134+ return out
135+ }
136+ out .ResourceRequest = cr .ResourceRequest
137+ out .PriorityClassName = cr .PriorityClassName
138+ if cr .NodeClaim != nil {
139+ out .NodeClaim = & pb.NodeClaim {
140+ NodeAffinity : cr .NodeClaim .HardNodeAffinity ,
141+ NodeSelector : cr .NodeClaim .NodeSelector ,
142+ Tolerations : cr .NodeClaim .Tolerations ,
143+ }
144+ }
145+ return out
146+ }
147+
89148func (se * SchedulerEstimator ) maxAvailableReplicas (ctx context.Context , cluster string , replicaRequirements * workv1alpha2.ReplicaRequirements ) (int32 , error ) {
90149 client , err := se .cache .GetClient (cluster )
91150 if err != nil {
@@ -167,3 +226,32 @@ func getClusterReplicasConcurrently(parentCtx context.Context, clusters []string
167226 }
168227 return clusterReplicas , utilerrors .AggregateGoroutines (funcs ... )
169228}
229+
230+ func getClusterComponentSetsConcurrently (
231+ parentCtx context.Context ,
232+ clusters []* clusterv1alpha1.Cluster ,
233+ timeout time.Duration ,
234+ getClusterSetsEstimation func (ctx context.Context , cluster string ) (int32 , error ),
235+ ) ([]ComponentSetEstimationResponse , error ) {
236+ // add object info to gRPC metadata
237+ if u , ok := parentCtx .Value (util .ContextKeyObject ).(string ); ok {
238+ parentCtx = metadata .AppendToOutgoingContext (parentCtx , string (util .ContextKeyObject ), u )
239+ }
240+ ctx , cancel := context .WithTimeout (parentCtx , timeout )
241+ defer cancel ()
242+
243+ results := make ([]ComponentSetEstimationResponse , len (clusters ))
244+ funcs := make ([]func () error , len (clusters ))
245+ for i , cluster := range clusters {
246+ localIndex , localCluster := i , cluster
247+ funcs [i ] = func () error {
248+ sets , err := getClusterSetsEstimation (ctx , localCluster .Name )
249+ if err != nil {
250+ return err
251+ }
252+ results [localIndex ] = ComponentSetEstimationResponse {Name : localCluster .Name , Sets : sets }
253+ return nil
254+ }
255+ }
256+ return results , utilerrors .AggregateGoroutines (funcs ... )
257+ }
0 commit comments