volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/rescheduling/rescheduling.go (about)

     1  /*
     2  Copyright 2022 The Volcano Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package rescheduling
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/mitchellh/mapstructure"
    23  
    24  	"k8s.io/klog/v2"
    25  
    26  	"volcano.sh/volcano/pkg/scheduler/api"
    27  	"volcano.sh/volcano/pkg/scheduler/framework"
    28  )
    29  
    30  const (
    31  	// PluginName indicates name of volcano scheduler plugin
    32  	PluginName = "rescheduling"
    33  	// DefaultInterval indicates the default interval rescheduling plugin works for
    34  	DefaultInterval = 5 * time.Minute
    35  	// DefaultMetricsPeriod indicates the default metrics period rescheduling plugin works for
    36  	DefaultMetricsPeriod = "5m"
    37  	// DefaultStrategy indicates the default strategy rescheduling plugin making use of
    38  	DefaultStrategy = "lowNodeUtilization"
    39  )
    40  
    41  var (
    42  	// Session contains all the data in session object which will be used for all the rescheduling package
    43  	Session *framework.Session
    44  
    45  	// RegisteredStrategyConfigs collects all the strategy configurations registered.
    46  	RegisteredStrategyConfigs map[string]interface{}
    47  
    48  	// VictimFn contains all the VictimTasksFn for registered the strategies
    49  	VictimFn map[string]api.VictimTasksFn
    50  
    51  	// MetricsPeriod indicates the metrics period will be used during this plugin. 5 minutes by default.
    52  	MetricsPeriod string
    53  )
    54  
    55  func init() {
    56  	RegisteredStrategyConfigs = make(map[string]interface{})
    57  	VictimFn = make(map[string]api.VictimTasksFn)
    58  	MetricsPeriod = "5m"
    59  
    60  	// register victim functions for all strategies here
    61  	VictimFn["lowNodeUtilization"] = victimsFnForLnu
    62  }
    63  
    64  type reschedulingPlugin struct {
    65  	// Arguments given for rescheduling plugin
    66  	pluginArguments framework.Arguments
    67  }
    68  
    69  // New function returns rescheduling plugin object
    70  func New(arguments framework.Arguments) framework.Plugin {
    71  	return &reschedulingPlugin{
    72  		pluginArguments: arguments,
    73  	}
    74  }
    75  
    76  // Name returns the name of rescheduling plugin
    77  func (rp *reschedulingPlugin) Name() string {
    78  	return PluginName
    79  }
    80  
    81  func (rp *reschedulingPlugin) OnSessionOpen(ssn *framework.Session) {
    82  	klog.V(5).Infof("Enter rescheduling plugin ...")
    83  	defer klog.V(5).Infof("Leaving rescheduling plugin.")
    84  
    85  	// Parse all the rescheduling strategies and execution interval
    86  	Session = ssn
    87  	configs := NewReschedulingConfigs()
    88  	for _, tier := range ssn.Tiers {
    89  		for _, pluginOption := range tier.Plugins {
    90  			if pluginOption.Name == PluginName {
    91  				configs.parseArguments(pluginOption.Arguments)
    92  				break
    93  			}
    94  		}
    95  	}
    96  
    97  	if !timeToRun(configs.interval) {
    98  		klog.V(3).Infof("It is not the time to execute rescheduling strategies.")
    99  		return
   100  	}
   101  
   102  	// Get all strategies and register the victim functions for each strategy.
   103  	victimFns := make([]api.VictimTasksFn, 0)
   104  	for _, strategy := range configs.strategies {
   105  		if VictimFn[strategy.Name] != nil {
   106  			klog.V(4).Infof("strategy: %s\n", strategy.Name)
   107  			victimFns = append(victimFns, VictimFn[strategy.Name])
   108  		}
   109  	}
   110  	ssn.AddVictimTasksFns(rp.Name(), victimFns)
   111  }
   112  
   113  func (rp *reschedulingPlugin) OnSessionClose(ssn *framework.Session) {
   114  	Session = nil
   115  	for k := range RegisteredStrategyConfigs {
   116  		delete(RegisteredStrategyConfigs, k)
   117  	}
   118  }
   119  
   120  // Configs is the struct for rescheduling plugin arguments
   121  type Configs struct {
   122  	interval   time.Duration
   123  	strategies []Strategy
   124  }
   125  
   126  // Strategy is the struct for rescheduling strategy
   127  type Strategy struct {
   128  	Name   string                 `json:"name"`
   129  	Params map[string]interface{} `json:"params"`
   130  }
   131  
   132  // NewReschedulingConfigs creates an object of rescheduling configurations with default configuration
   133  func NewReschedulingConfigs() *Configs {
   134  	config := &Configs{
   135  		interval: DefaultInterval,
   136  		strategies: []Strategy{
   137  			{
   138  				Name:   DefaultStrategy,
   139  				Params: DefaultLowNodeConf,
   140  			},
   141  		},
   142  	}
   143  	RegisteredStrategyConfigs[DefaultStrategy] = DefaultLowNodeConf
   144  	return config
   145  }
   146  
   147  // parseArguments parse all the rescheduling arguments
   148  func (rc *Configs) parseArguments(arguments framework.Arguments) {
   149  	var intervalStr string
   150  	var err error
   151  	if intervalArg, ok := arguments["interval"]; ok {
   152  		intervalStr = intervalArg.(string)
   153  	}
   154  	rc.interval, err = time.ParseDuration(intervalStr)
   155  	if err != nil {
   156  		klog.V(4).Infof("Parse rescheduling interval failed. Reset the interval to 5m by default.")
   157  		rc.interval = DefaultInterval
   158  	}
   159  	if metricsPeriodArg, ok := arguments["metricsPeriod"]; ok {
   160  		MetricsPeriod = metricsPeriodArg.(string)
   161  	}
   162  	if MetricsPeriod == "" {
   163  		MetricsPeriod = DefaultMetricsPeriod
   164  	}
   165  	strategies, ok := arguments["strategies"]
   166  	if ok {
   167  		strategyArray, _ := strategies.([]interface{})
   168  		if len(strategyArray) != 0 {
   169  			rc.strategies = rc.strategies[0:0]
   170  		}
   171  		for _, strategyInterface := range strategyArray {
   172  			strategy := new(Strategy)
   173  			err := mapstructure.Decode(strategyInterface, strategy)
   174  			if err != nil {
   175  				klog.V(3).Infof("Decode error: %s\n", err.Error())
   176  			} else {
   177  				rc.strategies = append(rc.strategies, *strategy)
   178  			}
   179  		}
   180  		for k := range RegisteredStrategyConfigs {
   181  			delete(RegisteredStrategyConfigs, k)
   182  		}
   183  		for _, strategy := range rc.strategies {
   184  			RegisteredStrategyConfigs[strategy.Name] = strategy.Params
   185  		}
   186  		klog.V(3).Infof("RegisteredStrategyConfigs: %v\n", RegisteredStrategyConfigs)
   187  	}
   188  	for _, strategy := range rc.strategies {
   189  		klog.V(3).Infof("strategy: %s, params: %v\n", strategy.Name, strategy.Params)
   190  	}
   191  }