mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-11-01 22:34:14 +00:00
adding validation for componentconfig
adding validation to cmd kube-scheduler
Add support for ipv6 in IsValidSocketAddr function
updating copyright date in componentconfig/validation/validation.go
updating copyright date in componentconfig/validation/validation_test.go
adding validation for cli options
adding BUILD files
updating validate function to return []errors in cmd/kube-scheduler
ok, really returning []error this time
adding comments for exported componentconfig Validation functions
silly me, not checking structs along the way :'(
refactor to avoid else statement
moving policy nil check up one function
rejigging some deprecated cmd validations
stumbling my way around validation slowly but surely
updating according to review from @bsalamat
- not validating leader election config unless leader election is enabled
- leader election time values cannot be zero
- removing validation for KubeConfigFile
- removing validation for scheduler policy
leader elect options should be non-negative
adding test cases for renewDeadline and leaseDuration being zero
fixing logic in componentconfig validation 😅
removing KubeConfigFile reference from tests as it was removed in master
2ff9bd6699
removing bogus space after var assignment
adding more tests for componentconfig based on feedback
making updates to validation because types were moved on master
update bazel build
adding validation for staging/apimachinery
adding validation for staging/apiserver
adding fieldPaths for staging validations
moving staging validations out of componentconfig
updating test case scenario for staging/apimachinery
./hack/update-bazel.sh
moving kube-scheduler validations from componentconfig
./hack/update-bazel.sh
removing non-negative check for QPS
resourceLock required
adding HardPodAffinitySymmetricWeight 0-100 range to cmd flag help section
310 lines
11 KiB
Go
310 lines
11 KiB
Go
/*
|
|
Copyright 2018 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package options
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/spf13/pflag"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
apimachineryconfig "k8s.io/apimachinery/pkg/apis/config"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/uuid"
|
|
apiserveroptions "k8s.io/apiserver/pkg/server/options"
|
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
"k8s.io/client-go/informers"
|
|
clientset "k8s.io/client-go/kubernetes"
|
|
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
|
restclient "k8s.io/client-go/rest"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
"k8s.io/client-go/tools/leaderelection"
|
|
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
|
"k8s.io/client-go/tools/record"
|
|
kubeschedulerconfigv1alpha1 "k8s.io/kube-scheduler/config/v1alpha1"
|
|
schedulerappconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
|
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
|
"k8s.io/kubernetes/pkg/client/leaderelectionconfig"
|
|
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
|
kubeschedulerscheme "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
|
|
"k8s.io/kubernetes/pkg/scheduler/factory"
|
|
)
|
|
|
|
// Options has all the params needed to run a Scheduler
|
|
type Options struct {
|
|
// The default values. These are overridden if ConfigFile is set or by values in InsecureServing.
|
|
ComponentConfig kubeschedulerconfig.KubeSchedulerConfiguration
|
|
|
|
SecureServing *apiserveroptions.SecureServingOptions
|
|
CombinedInsecureServing *CombinedInsecureServingOptions
|
|
Authentication *apiserveroptions.DelegatingAuthenticationOptions
|
|
Authorization *apiserveroptions.DelegatingAuthorizationOptions
|
|
Deprecated *DeprecatedOptions
|
|
|
|
// ConfigFile is the location of the scheduler server's configuration file.
|
|
ConfigFile string
|
|
|
|
// WriteConfigTo is the path where the default configuration will be written.
|
|
WriteConfigTo string
|
|
|
|
Master string
|
|
}
|
|
|
|
// NewOptions returns default scheduler app options.
|
|
func NewOptions() (*Options, error) {
|
|
cfg, err := newDefaultComponentConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hhost, hport, err := splitHostIntPort(cfg.HealthzBindAddress)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
o := &Options{
|
|
ComponentConfig: *cfg,
|
|
SecureServing: nil, // TODO: enable with apiserveroptions.NewSecureServingOptions()
|
|
CombinedInsecureServing: &CombinedInsecureServingOptions{
|
|
Healthz: &apiserveroptions.DeprecatedInsecureServingOptions{
|
|
BindNetwork: "tcp",
|
|
},
|
|
Metrics: &apiserveroptions.DeprecatedInsecureServingOptions{
|
|
BindNetwork: "tcp",
|
|
},
|
|
BindPort: hport,
|
|
BindAddress: hhost,
|
|
},
|
|
Authentication: nil, // TODO: enable with apiserveroptions.NewDelegatingAuthenticationOptions()
|
|
Authorization: nil, // TODO: enable with apiserveroptions.NewDelegatingAuthorizationOptions()
|
|
Deprecated: &DeprecatedOptions{
|
|
UseLegacyPolicyConfig: false,
|
|
PolicyConfigMapNamespace: metav1.NamespaceSystem,
|
|
},
|
|
}
|
|
|
|
return o, nil
|
|
}
|
|
|
|
func splitHostIntPort(s string) (string, int, error) {
|
|
host, port, err := net.SplitHostPort(s)
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
portInt, err := strconv.Atoi(port)
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
return host, portInt, err
|
|
}
|
|
|
|
func newDefaultComponentConfig() (*kubeschedulerconfig.KubeSchedulerConfiguration, error) {
|
|
cfgv1alpha1 := kubeschedulerconfigv1alpha1.KubeSchedulerConfiguration{}
|
|
kubeschedulerscheme.Scheme.Default(&cfgv1alpha1)
|
|
cfg := kubeschedulerconfig.KubeSchedulerConfiguration{}
|
|
if err := kubeschedulerscheme.Scheme.Convert(&cfgv1alpha1, &cfg, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
return &cfg, nil
|
|
}
|
|
|
|
// AddFlags adds flags for the scheduler options.
|
|
func (o *Options) AddFlags(fs *pflag.FlagSet) {
|
|
fs.StringVar(&o.ConfigFile, "config", o.ConfigFile, "The path to the configuration file. Flags override values in this file.")
|
|
fs.StringVar(&o.WriteConfigTo, "write-config-to", o.WriteConfigTo, "If set, write the configuration values to this file and exit.")
|
|
fs.StringVar(&o.Master, "master", o.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
|
|
|
|
o.SecureServing.AddFlags(fs)
|
|
o.CombinedInsecureServing.AddFlags(fs)
|
|
o.Authentication.AddFlags(fs)
|
|
o.Authorization.AddFlags(fs)
|
|
o.Deprecated.AddFlags(fs, &o.ComponentConfig)
|
|
|
|
leaderelectionconfig.BindFlags(&o.ComponentConfig.LeaderElection.LeaderElectionConfiguration, fs)
|
|
utilfeature.DefaultFeatureGate.AddFlag(fs)
|
|
}
|
|
|
|
// ApplyTo applies the scheduler options to the given scheduler app configuration.
|
|
func (o *Options) ApplyTo(c *schedulerappconfig.Config) error {
|
|
if len(o.ConfigFile) == 0 {
|
|
c.ComponentConfig = o.ComponentConfig
|
|
|
|
// only apply deprecated flags if no config file is loaded (this is the old behaviour).
|
|
if err := o.Deprecated.ApplyTo(&c.ComponentConfig); err != nil {
|
|
return err
|
|
}
|
|
if err := o.CombinedInsecureServing.ApplyTo(c, &c.ComponentConfig); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
cfg, err := loadConfigFromFile(o.ConfigFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// use the loaded config file only, with the exception of --address and --port. This means that
|
|
// none of the deprectated flags in o.Deprecated are taken into consideration. This is the old
|
|
// behaviour of the flags we have to keep.
|
|
c.ComponentConfig = *cfg
|
|
|
|
if err := o.CombinedInsecureServing.ApplyToFromLoadedConfig(c, &c.ComponentConfig); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := o.SecureServing.ApplyTo(&c.SecureServing); err != nil {
|
|
return err
|
|
}
|
|
if err := o.Authentication.ApplyTo(&c.Authentication, c.SecureServing, nil); err != nil {
|
|
return err
|
|
}
|
|
return o.Authorization.ApplyTo(&c.Authorization)
|
|
}
|
|
|
|
// Validate validates all the required options.
|
|
func (o *Options) Validate() []error {
|
|
var errs []error
|
|
|
|
if err := validation.ValidateKubeSchedulerConfiguration(&o.ComponentConfig).ToAggregate(); err != nil {
|
|
errs = append(errs, err.Errors()...)
|
|
}
|
|
errs = append(errs, o.SecureServing.Validate()...)
|
|
errs = append(errs, o.CombinedInsecureServing.Validate()...)
|
|
errs = append(errs, o.Authentication.Validate()...)
|
|
errs = append(errs, o.Authorization.Validate()...)
|
|
errs = append(errs, o.Deprecated.Validate()...)
|
|
|
|
return errs
|
|
}
|
|
|
|
// Config return a scheduler config object
|
|
func (o *Options) Config() (*schedulerappconfig.Config, error) {
|
|
c := &schedulerappconfig.Config{}
|
|
if err := o.ApplyTo(c); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// prepare kube clients.
|
|
client, leaderElectionClient, eventClient, err := createClients(c.ComponentConfig.ClientConnection, o.Master, c.ComponentConfig.LeaderElection.RenewDeadline.Duration)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Prepare event clients.
|
|
eventBroadcaster := record.NewBroadcaster()
|
|
recorder := eventBroadcaster.NewRecorder(legacyscheme.Scheme, corev1.EventSource{Component: c.ComponentConfig.SchedulerName})
|
|
|
|
// Set up leader election if enabled.
|
|
var leaderElectionConfig *leaderelection.LeaderElectionConfig
|
|
if c.ComponentConfig.LeaderElection.LeaderElect {
|
|
leaderElectionConfig, err = makeLeaderElectionConfig(c.ComponentConfig.LeaderElection, leaderElectionClient, recorder)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
c.Client = client
|
|
c.InformerFactory = informers.NewSharedInformerFactory(client, 0)
|
|
c.PodInformer = factory.NewPodInformer(client, 0)
|
|
c.EventClient = eventClient
|
|
c.Recorder = recorder
|
|
c.Broadcaster = eventBroadcaster
|
|
c.LeaderElection = leaderElectionConfig
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// makeLeaderElectionConfig builds a leader election configuration. It will
|
|
// create a new resource lock associated with the configuration.
|
|
func makeLeaderElectionConfig(config kubeschedulerconfig.KubeSchedulerLeaderElectionConfiguration, client clientset.Interface, recorder record.EventRecorder) (*leaderelection.LeaderElectionConfig, error) {
|
|
hostname, err := os.Hostname()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to get hostname: %v", err)
|
|
}
|
|
// add a uniquifier so that two processes on the same host don't accidentally both become active
|
|
id := hostname + "_" + string(uuid.NewUUID())
|
|
|
|
rl, err := resourcelock.New(config.ResourceLock,
|
|
config.LockObjectNamespace,
|
|
config.LockObjectName,
|
|
client.CoreV1(),
|
|
resourcelock.ResourceLockConfig{
|
|
Identity: id,
|
|
EventRecorder: recorder,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("couldn't create resource lock: %v", err)
|
|
}
|
|
|
|
return &leaderelection.LeaderElectionConfig{
|
|
Lock: rl,
|
|
LeaseDuration: config.LeaseDuration.Duration,
|
|
RenewDeadline: config.RenewDeadline.Duration,
|
|
RetryPeriod: config.RetryPeriod.Duration,
|
|
}, nil
|
|
}
|
|
|
|
// createClients creates a kube client and an event client from the given config and masterOverride.
|
|
// TODO remove masterOverride when CLI flags are removed.
|
|
func createClients(config apimachineryconfig.ClientConnectionConfiguration, masterOverride string, timeout time.Duration) (clientset.Interface, clientset.Interface, v1core.EventsGetter, error) {
|
|
if len(config.Kubeconfig) == 0 && len(masterOverride) == 0 {
|
|
glog.Warningf("Neither --kubeconfig nor --master was specified. Using default API client. This might not work.")
|
|
}
|
|
|
|
// This creates a client, first loading any specified kubeconfig
|
|
// file, and then overriding the Master flag, if non-empty.
|
|
kubeConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
|
&clientcmd.ClientConfigLoadingRules{ExplicitPath: config.Kubeconfig},
|
|
&clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterOverride}}).ClientConfig()
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
kubeConfig.AcceptContentTypes = config.AcceptContentTypes
|
|
kubeConfig.ContentType = config.ContentType
|
|
kubeConfig.QPS = config.QPS
|
|
//TODO make config struct use int instead of int32?
|
|
kubeConfig.Burst = int(config.Burst)
|
|
|
|
client, err := clientset.NewForConfig(restclient.AddUserAgent(kubeConfig, "scheduler"))
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
// shallow copy, do not modify the kubeConfig.Timeout.
|
|
restConfig := *kubeConfig
|
|
restConfig.Timeout = timeout
|
|
leaderElectionClient, err := clientset.NewForConfig(restclient.AddUserAgent(&restConfig, "leader-election"))
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
eventClient, err := clientset.NewForConfig(kubeConfig)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
return client, leaderElectionClient, eventClient.CoreV1(), nil
|
|
}
|