1
16
17 package options
18
19 import (
20 "context"
21 "fmt"
22 "net"
23 "os"
24 "time"
25
26 corev1 "k8s.io/api/core/v1"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/util/uuid"
29 apiserveroptions "k8s.io/apiserver/pkg/server/options"
30 utilfeature "k8s.io/apiserver/pkg/util/feature"
31 "k8s.io/client-go/dynamic"
32 "k8s.io/client-go/dynamic/dynamicinformer"
33 clientset "k8s.io/client-go/kubernetes"
34 restclient "k8s.io/client-go/rest"
35 "k8s.io/client-go/tools/clientcmd"
36 "k8s.io/client-go/tools/events"
37 "k8s.io/client-go/tools/leaderelection"
38 "k8s.io/client-go/tools/leaderelection/resourcelock"
39 "k8s.io/client-go/tools/record"
40 cliflag "k8s.io/component-base/cli/flag"
41 componentbaseconfig "k8s.io/component-base/config"
42 "k8s.io/component-base/config/options"
43 "k8s.io/component-base/logs"
44 logsapi "k8s.io/component-base/logs/api/v1"
45 "k8s.io/component-base/metrics"
46 "k8s.io/klog/v2"
47 schedulerappconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
48 "k8s.io/kubernetes/pkg/scheduler"
49 kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
50 "k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
51 netutils "k8s.io/utils/net"
52 )
53
54
55 type Options struct {
56
57 ComponentConfig *kubeschedulerconfig.KubeSchedulerConfiguration
58
59 SecureServing *apiserveroptions.SecureServingOptionsWithLoopback
60 Authentication *apiserveroptions.DelegatingAuthenticationOptions
61 Authorization *apiserveroptions.DelegatingAuthorizationOptions
62 Metrics *metrics.Options
63 Logs *logs.Options
64 Deprecated *DeprecatedOptions
65 LeaderElection *componentbaseconfig.LeaderElectionConfiguration
66
67
68 ConfigFile string
69
70
71 WriteConfigTo string
72
73 Master string
74
75
76 Flags *cliflag.NamedFlagSets
77 }
78
79
80 func NewOptions() *Options {
81 o := &Options{
82 SecureServing: apiserveroptions.NewSecureServingOptions().WithLoopback(),
83 Authentication: apiserveroptions.NewDelegatingAuthenticationOptions(),
84 Authorization: apiserveroptions.NewDelegatingAuthorizationOptions(),
85 Deprecated: &DeprecatedOptions{
86 PodMaxInUnschedulablePodsDuration: 5 * time.Minute,
87 },
88 LeaderElection: &componentbaseconfig.LeaderElectionConfiguration{
89 LeaderElect: true,
90 LeaseDuration: metav1.Duration{Duration: 15 * time.Second},
91 RenewDeadline: metav1.Duration{Duration: 10 * time.Second},
92 RetryPeriod: metav1.Duration{Duration: 2 * time.Second},
93 ResourceLock: "leases",
94 ResourceName: "kube-scheduler",
95 ResourceNamespace: "kube-system",
96 },
97 Metrics: metrics.NewOptions(),
98 Logs: logs.NewOptions(),
99 }
100
101 o.Authentication.TolerateInClusterLookupFailure = true
102 o.Authentication.RemoteKubeConfigFileOptional = true
103 o.Authorization.RemoteKubeConfigFileOptional = true
104
105
106 o.SecureServing.ServerCert.CertDirectory = ""
107 o.SecureServing.ServerCert.PairName = "kube-scheduler"
108 o.SecureServing.BindPort = kubeschedulerconfig.DefaultKubeSchedulerPort
109
110 o.initFlags()
111
112 return o
113 }
114
115
116 func (o *Options) ApplyDeprecated() {
117 if o.Flags == nil {
118 return
119 }
120
121 deprecated := o.Flags.FlagSet("deprecated")
122 if deprecated.Changed("profiling") {
123 o.ComponentConfig.EnableProfiling = o.Deprecated.EnableProfiling
124 }
125 if deprecated.Changed("contention-profiling") {
126 o.ComponentConfig.EnableContentionProfiling = o.Deprecated.EnableContentionProfiling
127 }
128 if deprecated.Changed("kubeconfig") {
129 o.ComponentConfig.ClientConnection.Kubeconfig = o.Deprecated.Kubeconfig
130 }
131 if deprecated.Changed("kube-api-content-type") {
132 o.ComponentConfig.ClientConnection.ContentType = o.Deprecated.ContentType
133 }
134 if deprecated.Changed("kube-api-qps") {
135 o.ComponentConfig.ClientConnection.QPS = o.Deprecated.QPS
136 }
137 if deprecated.Changed("kube-api-burst") {
138 o.ComponentConfig.ClientConnection.Burst = o.Deprecated.Burst
139 }
140 }
141
142
143
144 func (o *Options) ApplyLeaderElectionTo(cfg *kubeschedulerconfig.KubeSchedulerConfiguration) {
145 if o.Flags == nil {
146 return
147 }
148
149 leaderelection := o.Flags.FlagSet("leader election")
150 if leaderelection.Changed("leader-elect") {
151 cfg.LeaderElection.LeaderElect = o.LeaderElection.LeaderElect
152 }
153 if leaderelection.Changed("leader-elect-lease-duration") {
154 cfg.LeaderElection.LeaseDuration = o.LeaderElection.LeaseDuration
155 }
156 if leaderelection.Changed("leader-elect-renew-deadline") {
157 cfg.LeaderElection.RenewDeadline = o.LeaderElection.RenewDeadline
158 }
159 if leaderelection.Changed("leader-elect-retry-period") {
160 cfg.LeaderElection.RetryPeriod = o.LeaderElection.RetryPeriod
161 }
162 if leaderelection.Changed("leader-elect-resource-lock") {
163 cfg.LeaderElection.ResourceLock = o.LeaderElection.ResourceLock
164 }
165 if leaderelection.Changed("leader-elect-resource-name") {
166 cfg.LeaderElection.ResourceName = o.LeaderElection.ResourceName
167 }
168 if leaderelection.Changed("leader-elect-resource-namespace") {
169 cfg.LeaderElection.ResourceNamespace = o.LeaderElection.ResourceNamespace
170 }
171
172 o.ComponentConfig = cfg
173 }
174
175
176 func (o *Options) initFlags() {
177 if o.Flags != nil {
178 return
179 }
180
181 nfs := cliflag.NamedFlagSets{}
182 fs := nfs.FlagSet("misc")
183 fs.StringVar(&o.ConfigFile, "config", o.ConfigFile, "The path to the configuration file.")
184 fs.StringVar(&o.WriteConfigTo, "write-config-to", o.WriteConfigTo, "If set, write the configuration values to this file and exit.")
185 fs.StringVar(&o.Master, "master", o.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
186
187 o.SecureServing.AddFlags(nfs.FlagSet("secure serving"))
188 o.Authentication.AddFlags(nfs.FlagSet("authentication"))
189 o.Authorization.AddFlags(nfs.FlagSet("authorization"))
190 o.Deprecated.AddFlags(nfs.FlagSet("deprecated"))
191 options.BindLeaderElectionFlags(o.LeaderElection, nfs.FlagSet("leader election"))
192 utilfeature.DefaultMutableFeatureGate.AddFlag(nfs.FlagSet("feature gate"))
193 o.Metrics.AddFlags(nfs.FlagSet("metrics"))
194 logsapi.AddFlags(o.Logs, nfs.FlagSet("logs"))
195
196 o.Flags = &nfs
197 }
198
199
200 func (o *Options) ApplyTo(logger klog.Logger, c *schedulerappconfig.Config) error {
201 if len(o.ConfigFile) == 0 {
202
203 o.ApplyDeprecated()
204 o.ApplyLeaderElectionTo(o.ComponentConfig)
205 c.ComponentConfig = *o.ComponentConfig
206 } else {
207 cfg, err := LoadConfigFromFile(logger, o.ConfigFile)
208 if err != nil {
209 return err
210 }
211
212 o.ApplyLeaderElectionTo(cfg)
213
214 if err := validation.ValidateKubeSchedulerConfiguration(cfg); err != nil {
215 return err
216 }
217
218 c.ComponentConfig = *cfg
219 }
220
221
222
223
224 kubeConfig, err := createKubeConfig(c.ComponentConfig.ClientConnection, o.Master)
225 if err != nil {
226 return err
227 }
228 c.KubeConfig = kubeConfig
229
230 if err := o.SecureServing.ApplyTo(&c.SecureServing, &c.LoopbackClientConfig); err != nil {
231 return err
232 }
233 if o.SecureServing != nil && (o.SecureServing.BindPort != 0 || o.SecureServing.Listener != nil) {
234 if err := o.Authentication.ApplyTo(&c.Authentication, c.SecureServing, nil); err != nil {
235 return err
236 }
237 if err := o.Authorization.ApplyTo(&c.Authorization); err != nil {
238 return err
239 }
240 }
241 o.Metrics.Apply()
242
243
244 if o.Deprecated != nil {
245 c.PodMaxInUnschedulablePodsDuration = o.Deprecated.PodMaxInUnschedulablePodsDuration
246 }
247
248 return nil
249 }
250
251
252 func (o *Options) Validate() []error {
253 var errs []error
254
255 if err := validation.ValidateKubeSchedulerConfiguration(o.ComponentConfig); err != nil {
256 errs = append(errs, err.Errors()...)
257 }
258 errs = append(errs, o.SecureServing.Validate()...)
259 errs = append(errs, o.Authentication.Validate()...)
260 errs = append(errs, o.Authorization.Validate()...)
261 errs = append(errs, o.Metrics.Validate()...)
262
263 return errs
264 }
265
266
267 func (o *Options) Config(ctx context.Context) (*schedulerappconfig.Config, error) {
268 logger := klog.FromContext(ctx)
269 if o.SecureServing != nil {
270 if err := o.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{netutils.ParseIPSloppy("127.0.0.1")}); err != nil {
271 return nil, fmt.Errorf("error creating self-signed certificates: %v", err)
272 }
273 }
274
275 c := &schedulerappconfig.Config{}
276 if err := o.ApplyTo(logger, c); err != nil {
277 return nil, err
278 }
279
280
281 client, eventClient, err := createClients(c.KubeConfig)
282 if err != nil {
283 return nil, err
284 }
285
286 c.EventBroadcaster = events.NewEventBroadcasterAdapterWithContext(ctx, eventClient)
287
288
289 var leaderElectionConfig *leaderelection.LeaderElectionConfig
290 if c.ComponentConfig.LeaderElection.LeaderElect {
291
292 schedulerName := corev1.DefaultSchedulerName
293 if len(c.ComponentConfig.Profiles) != 0 {
294 schedulerName = c.ComponentConfig.Profiles[0].SchedulerName
295 }
296 coreRecorder := c.EventBroadcaster.DeprecatedNewLegacyRecorder(schedulerName)
297 leaderElectionConfig, err = makeLeaderElectionConfig(c.ComponentConfig.LeaderElection, c.KubeConfig, coreRecorder)
298 if err != nil {
299 return nil, err
300 }
301 }
302
303 c.Client = client
304 c.InformerFactory = scheduler.NewInformerFactory(client, 0)
305 dynClient := dynamic.NewForConfigOrDie(c.KubeConfig)
306 c.DynInformerFactory = dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynClient, 0, corev1.NamespaceAll, nil)
307 c.LeaderElection = leaderElectionConfig
308
309 return c, nil
310 }
311
312
313
314 func makeLeaderElectionConfig(config componentbaseconfig.LeaderElectionConfiguration, kubeConfig *restclient.Config, recorder record.EventRecorder) (*leaderelection.LeaderElectionConfig, error) {
315 hostname, err := os.Hostname()
316 if err != nil {
317 return nil, fmt.Errorf("unable to get hostname: %v", err)
318 }
319
320 id := hostname + "_" + string(uuid.NewUUID())
321
322 rl, err := resourcelock.NewFromKubeconfig(config.ResourceLock,
323 config.ResourceNamespace,
324 config.ResourceName,
325 resourcelock.ResourceLockConfig{
326 Identity: id,
327 EventRecorder: recorder,
328 },
329 kubeConfig,
330 config.RenewDeadline.Duration)
331 if err != nil {
332 return nil, fmt.Errorf("couldn't create resource lock: %v", err)
333 }
334
335 return &leaderelection.LeaderElectionConfig{
336 Lock: rl,
337 LeaseDuration: config.LeaseDuration.Duration,
338 RenewDeadline: config.RenewDeadline.Duration,
339 RetryPeriod: config.RetryPeriod.Duration,
340 WatchDog: leaderelection.NewLeaderHealthzAdaptor(time.Second * 20),
341 Name: "kube-scheduler",
342 ReleaseOnCancel: true,
343 }, nil
344 }
345
346
347
348 func createKubeConfig(config componentbaseconfig.ClientConnectionConfiguration, masterOverride string) (*restclient.Config, error) {
349 kubeConfig, err := clientcmd.BuildConfigFromFlags(masterOverride, config.Kubeconfig)
350 if err != nil {
351 return nil, err
352 }
353
354 kubeConfig.DisableCompression = true
355 kubeConfig.AcceptContentTypes = config.AcceptContentTypes
356 kubeConfig.ContentType = config.ContentType
357 kubeConfig.QPS = config.QPS
358 kubeConfig.Burst = int(config.Burst)
359
360 return kubeConfig, nil
361 }
362
363
364 func createClients(kubeConfig *restclient.Config) (clientset.Interface, clientset.Interface, error) {
365 client, err := clientset.NewForConfig(restclient.AddUserAgent(kubeConfig, "scheduler"))
366 if err != nil {
367 return nil, nil, err
368 }
369
370 eventClient, err := clientset.NewForConfig(kubeConfig)
371 if err != nil {
372 return nil, nil, err
373 }
374
375 return client, eventClient, nil
376 }
377
View as plain text