package addon import ( "context" "fmt" "k8s.io/klog/v2" "k8s.io/utils/clock" clusterapiv1 "open-cluster-management.io/api/cluster/v1" clusterapiv1beta1 "open-cluster-management.io/api/cluster/v1beta1" "open-cluster-management.io/ocm/pkg/placement/controllers/framework" "open-cluster-management.io/ocm/pkg/placement/plugins" ) const ( placementLabel = clusterapiv1beta1.PlacementLabel description = ` Customize prioritizer get cluster scores from AddOnPlacementScores with sepcific resource name and score name. The clusters which doesn't have corresponding AddOnPlacementScores resource or has expired score is given score 0. ` ) var _ plugins.Prioritizer = &AddOn{} var AddOnClock = clock.Clock(clock.RealClock{}) type AddOn struct { handle plugins.Handle prioritizerName string resourceName string scoreName string } type AddOnBuilder struct { addOn *AddOn } func NewAddOnPrioritizerBuilder(handle plugins.Handle) *AddOnBuilder { return &AddOnBuilder{ addOn: &AddOn{ handle: handle, }, } } func (c *AddOnBuilder) WithResourceName(name string) *AddOnBuilder { c.addOn.resourceName = name return c } func (c *AddOnBuilder) WithScoreName(name string) *AddOnBuilder { c.addOn.scoreName = name return c } func (c *AddOnBuilder) Build() *AddOn { c.addOn.prioritizerName = "AddOn" + "/" + c.addOn.resourceName + "/" + c.addOn.scoreName return c.addOn } func (c *AddOn) Name() string { return c.prioritizerName } func (c *AddOn) Description() string { return description } func (c *AddOn) Score(ctx context.Context, placement *clusterapiv1beta1.Placement, clusters []*clusterapiv1.ManagedCluster) (plugins.PluginScoreResult, *framework.Status) { scores := map[string]int64{} expiredScores := "" status := framework.NewStatus(c.Name(), framework.Success, "") for _, cluster := range clusters { namespace := cluster.Name // default score is 0 scores[cluster.Name] = 0 // get AddOnPlacementScores CR with resourceName addOnScores, err := c.handle.ScoreLister().AddOnPlacementScores(namespace).Get(c.resourceName) if err != nil { klog.FromContext(ctx).Info("Failed to get AddOnPlacementScores", "error", err) continue } // check score valid time if (addOnScores.Status.ValidUntil != nil) && AddOnClock.Now().After(addOnScores.Status.ValidUntil.Time) { expiredScores = fmt.Sprintf("%s %s/%s", expiredScores, namespace, c.resourceName) continue } // get AddOnPlacementScores score with scoreName for _, v := range addOnScores.Status.Scores { if v.Name == c.scoreName { scores[cluster.Name] = int64(v.Value) } } } if len(expiredScores) > 0 { status = framework.NewStatus( c.Name(), framework.Warning, fmt.Sprintf("AddOnPlacementScores%s expired", expiredScores), ) } return plugins.PluginScoreResult{ Scores: scores, }, status } func (c *AddOn) RequeueAfter(ctx context.Context, placement *clusterapiv1beta1.Placement) (plugins.PluginRequeueResult, *framework.Status) { return plugins.PluginRequeueResult{}, framework.NewStatus(c.Name(), framework.Success, "") }