2023-05-29 21:03:29 +00:00
/ *
Copyright 2016 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"
"math/rand"
"net"
"time"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
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"
"k8s.io/client-go/kubernetes/scheme"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/record"
cloudprovider "k8s.io/cloud-provider"
"k8s.io/cloud-provider/app/config"
ccmconfig "k8s.io/cloud-provider/config"
ccmconfigscheme "k8s.io/cloud-provider/config/install"
ccmconfigv1alpha1 "k8s.io/cloud-provider/config/v1alpha1"
2023-08-17 05:15:28 +00:00
"k8s.io/cloud-provider/names"
2023-05-29 21:03:29 +00:00
cliflag "k8s.io/component-base/cli/flag"
cmoptions "k8s.io/controller-manager/options"
"k8s.io/controller-manager/pkg/clientbuilder"
netutils "k8s.io/utils/net"
// add the related feature gates
_ "k8s.io/controller-manager/pkg/features/register"
)
const (
// CloudControllerManagerUserAgent is the userAgent name when starting cloud-controller managers.
CloudControllerManagerUserAgent = "cloud-controller-manager"
)
// CloudControllerManagerOptions is the main context object for the controller manager.
type CloudControllerManagerOptions struct {
Generic * cmoptions . GenericControllerManagerConfigurationOptions
KubeCloudShared * KubeCloudSharedOptions
ServiceController * ServiceControllerOptions
2023-06-01 16:58:10 +00:00
NodeController * NodeControllerOptions
2023-05-29 21:03:29 +00:00
SecureServing * apiserveroptions . SecureServingOptionsWithLoopback
Authentication * apiserveroptions . DelegatingAuthenticationOptions
Authorization * apiserveroptions . DelegatingAuthorizationOptions
2023-06-01 16:58:10 +00:00
Master string
WebhookServing * WebhookServingOptions
Webhook * WebhookOptions
2023-05-29 21:03:29 +00:00
// NodeStatusUpdateFrequency is the frequency at which the controller updates nodes' status
NodeStatusUpdateFrequency metav1 . Duration
}
2023-06-01 16:58:10 +00:00
// ProviderDefaults are provided by the consumer when calling
// NewCloudControllerManagerOptions(), so that they can customize certain flag
// default values.
type ProviderDefaults struct {
// WebhookBindAddress is the default address. It can be overridden by "--webhook-bind-address".
WebhookBindAddress * net . IP
// WebhookBindPort is the default port. It can be overridden by "--webhook-bind-port".
WebhookBindPort * int
}
2023-05-29 21:03:29 +00:00
// NewCloudControllerManagerOptions creates a new ExternalCMServer with a default config.
func NewCloudControllerManagerOptions ( ) ( * CloudControllerManagerOptions , error ) {
2023-06-01 16:58:10 +00:00
return NewCloudControllerManagerOptionsWithProviderDefaults ( ProviderDefaults { } )
}
// NewCloudControllerManagerOptionsWithProviderDefaults creates a new
// ExternalCMServer with a default config, but allows the cloud provider to
// override a select number of default option values.
func NewCloudControllerManagerOptionsWithProviderDefaults ( defaults ProviderDefaults ) ( * CloudControllerManagerOptions , error ) {
2023-05-29 21:03:29 +00:00
componentConfig , err := NewDefaultComponentConfig ( )
if err != nil {
return nil , err
}
s := CloudControllerManagerOptions {
Generic : cmoptions . NewGenericControllerManagerConfigurationOptions ( & componentConfig . Generic ) ,
KubeCloudShared : NewKubeCloudSharedOptions ( & componentConfig . KubeCloudShared ) ,
2023-06-01 16:58:10 +00:00
NodeController : & NodeControllerOptions {
NodeControllerConfiguration : & componentConfig . NodeController ,
} ,
2023-05-29 21:03:29 +00:00
ServiceController : & ServiceControllerOptions {
ServiceControllerConfiguration : & componentConfig . ServiceController ,
} ,
SecureServing : apiserveroptions . NewSecureServingOptions ( ) . WithLoopback ( ) ,
2023-06-01 16:58:10 +00:00
Webhook : NewWebhookOptions ( ) ,
WebhookServing : NewWebhookServingOptions ( defaults ) ,
2023-05-29 21:03:29 +00:00
Authentication : apiserveroptions . NewDelegatingAuthenticationOptions ( ) ,
Authorization : apiserveroptions . NewDelegatingAuthorizationOptions ( ) ,
NodeStatusUpdateFrequency : componentConfig . NodeStatusUpdateFrequency ,
}
s . Authentication . RemoteKubeConfigFileOptional = true
s . Authorization . RemoteKubeConfigFileOptional = true
// Set the PairName but leave certificate directory blank to generate in-memory by default
s . SecureServing . ServerCert . CertDirectory = ""
s . SecureServing . ServerCert . PairName = "cloud-controller-manager"
s . SecureServing . BindPort = cloudprovider . CloudControllerManagerPort
s . Generic . LeaderElection . ResourceName = "cloud-controller-manager"
s . Generic . LeaderElection . ResourceNamespace = "kube-system"
return & s , nil
}
// NewDefaultComponentConfig returns cloud-controller manager configuration object.
func NewDefaultComponentConfig ( ) ( * ccmconfig . CloudControllerManagerConfiguration , error ) {
versioned := & ccmconfigv1alpha1 . CloudControllerManagerConfiguration { }
ccmconfigscheme . Scheme . Default ( versioned )
internal := & ccmconfig . CloudControllerManagerConfiguration { }
if err := ccmconfigscheme . Scheme . Convert ( versioned , internal , nil ) ; err != nil {
return nil , err
}
2023-06-01 16:58:10 +00:00
2023-05-29 21:03:29 +00:00
return internal , nil
}
// Flags returns flags for a specific CloudController by section name
2023-08-17 05:15:28 +00:00
func ( o * CloudControllerManagerOptions ) Flags ( allControllers [ ] string , disabledByDefaultControllers [ ] string , controllerAliases map [ string ] string , allWebhooks , disabledByDefaultWebhooks [ ] string ) cliflag . NamedFlagSets {
2023-05-29 21:03:29 +00:00
fss := cliflag . NamedFlagSets { }
2023-08-17 05:15:28 +00:00
o . Generic . AddFlags ( & fss , allControllers , disabledByDefaultControllers , controllerAliases )
2023-05-29 21:03:29 +00:00
o . KubeCloudShared . AddFlags ( fss . FlagSet ( "generic" ) )
2023-08-17 05:15:28 +00:00
o . NodeController . AddFlags ( fss . FlagSet ( names . CloudNodeController ) )
o . ServiceController . AddFlags ( fss . FlagSet ( names . ServiceLBController ) )
2023-06-01 16:58:10 +00:00
if o . Webhook != nil {
o . Webhook . AddFlags ( fss . FlagSet ( "webhook" ) , allWebhooks , disabledByDefaultWebhooks )
}
if o . WebhookServing != nil {
o . WebhookServing . AddFlags ( fss . FlagSet ( "webhook serving" ) )
}
2023-05-29 21:03:29 +00:00
o . SecureServing . AddFlags ( fss . FlagSet ( "secure serving" ) )
o . Authentication . AddFlags ( fss . FlagSet ( "authentication" ) )
o . Authorization . AddFlags ( fss . FlagSet ( "authorization" ) )
fs := fss . FlagSet ( "misc" )
fs . StringVar ( & o . Master , "master" , o . Master , "The address of the Kubernetes API server (overrides any value in kubeconfig)." )
2023-06-01 16:58:10 +00:00
fs . StringVar ( & o . Generic . ClientConnection . Kubeconfig , "kubeconfig" , o . Generic . ClientConnection . Kubeconfig , "Path to kubeconfig file with authorization and master location information (the master location can be overridden by the master flag)." )
2023-05-29 21:03:29 +00:00
fs . DurationVar ( & o . NodeStatusUpdateFrequency . Duration , "node-status-update-frequency" , o . NodeStatusUpdateFrequency . Duration , "Specifies how often the controller updates nodes' status." )
utilfeature . DefaultMutableFeatureGate . AddFlag ( fss . FlagSet ( "generic" ) )
return fss
}
// ApplyTo fills up cloud controller manager config with options.
2023-08-17 05:15:28 +00:00
func ( o * CloudControllerManagerOptions ) ApplyTo ( c * config . Config , allControllers [ ] string , disabledByDefaultControllers [ ] string , controllerAliases map [ string ] string , userAgent string ) error {
2023-05-29 21:03:29 +00:00
var err error
// Build kubeconfig first to so that if it fails, it doesn't cause leaking
// goroutines (started from initializing secure serving - which underneath
// creates a queue which in its constructor starts a goroutine).
2023-06-01 16:58:10 +00:00
c . Kubeconfig , err = clientcmd . BuildConfigFromFlags ( o . Master , o . Generic . ClientConnection . Kubeconfig )
2023-05-29 21:03:29 +00:00
if err != nil {
return err
}
c . Kubeconfig . DisableCompression = true
c . Kubeconfig . ContentConfig . AcceptContentTypes = o . Generic . ClientConnection . AcceptContentTypes
c . Kubeconfig . ContentConfig . ContentType = o . Generic . ClientConnection . ContentType
c . Kubeconfig . QPS = o . Generic . ClientConnection . QPS
c . Kubeconfig . Burst = int ( o . Generic . ClientConnection . Burst )
2023-08-17 05:15:28 +00:00
if err = o . Generic . ApplyTo ( & c . ComponentConfig . Generic , allControllers , disabledByDefaultControllers , controllerAliases ) ; err != nil {
2023-05-29 21:03:29 +00:00
return err
}
if err = o . KubeCloudShared . ApplyTo ( & c . ComponentConfig . KubeCloudShared ) ; err != nil {
return err
}
if err = o . ServiceController . ApplyTo ( & c . ComponentConfig . ServiceController ) ; err != nil {
return err
}
2023-06-01 16:58:10 +00:00
if o . Webhook != nil {
if err = o . Webhook . ApplyTo ( & c . ComponentConfig . Webhook ) ; err != nil {
return err
}
}
if o . WebhookServing != nil {
if err = o . WebhookServing . ApplyTo ( & c . WebhookSecureServing ) ; err != nil {
return err
}
}
2023-05-29 21:03:29 +00:00
if err = o . SecureServing . ApplyTo ( & c . SecureServing , & c . LoopbackClientConfig ) ; err != nil {
return err
}
if o . SecureServing . BindPort != 0 || o . SecureServing . Listener != nil {
if err = o . Authentication . ApplyTo ( & c . Authentication , c . SecureServing , nil ) ; err != nil {
return err
}
if err = o . Authorization . ApplyTo ( & c . Authorization ) ; err != nil {
return err
}
}
c . Client , err = clientset . NewForConfig ( restclient . AddUserAgent ( c . Kubeconfig , userAgent ) )
if err != nil {
return err
}
c . EventBroadcaster = record . NewBroadcaster ( )
c . EventRecorder = c . EventBroadcaster . NewRecorder ( scheme . Scheme , v1 . EventSource { Component : userAgent } )
rootClientBuilder := clientbuilder . SimpleControllerClientBuilder {
ClientConfig : c . Kubeconfig ,
}
if c . ComponentConfig . KubeCloudShared . UseServiceAccountCredentials {
c . ClientBuilder = clientbuilder . NewDynamicClientBuilder (
restclient . AnonymousClientConfig ( c . Kubeconfig ) ,
c . Client . CoreV1 ( ) ,
metav1 . NamespaceSystem )
} else {
c . ClientBuilder = rootClientBuilder
}
c . VersionedClient = rootClientBuilder . ClientOrDie ( "shared-informers" )
c . SharedInformers = informers . NewSharedInformerFactory ( c . VersionedClient , resyncPeriod ( c ) ( ) )
// sync back to component config
// TODO: find more elegant way than syncing back the values.
c . ComponentConfig . NodeStatusUpdateFrequency = o . NodeStatusUpdateFrequency
2023-06-01 16:58:10 +00:00
c . ComponentConfig . NodeController . ConcurrentNodeSyncs = o . NodeController . ConcurrentNodeSyncs
2023-05-29 21:03:29 +00:00
return nil
}
// Validate is used to validate config before launching the cloud controller manager
2023-08-17 05:15:28 +00:00
func ( o * CloudControllerManagerOptions ) Validate ( allControllers [ ] string , disabledByDefaultControllers [ ] string , controllerAliases map [ string ] string , allWebhooks , disabledByDefaultWebhooks [ ] string ) error {
2023-05-29 21:03:29 +00:00
errors := [ ] error { }
2023-08-17 05:15:28 +00:00
errors = append ( errors , o . Generic . Validate ( allControllers , disabledByDefaultControllers , controllerAliases ) ... )
2023-05-29 21:03:29 +00:00
errors = append ( errors , o . KubeCloudShared . Validate ( ) ... )
errors = append ( errors , o . ServiceController . Validate ( ) ... )
errors = append ( errors , o . SecureServing . Validate ( ) ... )
errors = append ( errors , o . Authentication . Validate ( ) ... )
errors = append ( errors , o . Authorization . Validate ( ) ... )
2023-06-01 16:58:10 +00:00
if o . Webhook != nil {
errors = append ( errors , o . Webhook . Validate ( allWebhooks , disabledByDefaultWebhooks ) ... )
}
if o . WebhookServing != nil {
errors = append ( errors , o . WebhookServing . Validate ( ) ... )
if o . WebhookServing . BindPort == o . SecureServing . BindPort {
errors = append ( errors , fmt . Errorf ( "--webhook-secure-port cannot be the same value as --secure-port" ) )
}
}
2023-05-29 21:03:29 +00:00
if len ( o . KubeCloudShared . CloudProvider . Name ) == 0 {
errors = append ( errors , fmt . Errorf ( "--cloud-provider cannot be empty" ) )
}
return utilerrors . NewAggregate ( errors )
}
// resyncPeriod computes the time interval a shared informer waits before resyncing with the api server
func resyncPeriod ( c * config . Config ) func ( ) time . Duration {
return func ( ) time . Duration {
factor := rand . Float64 ( ) + 1
return time . Duration ( float64 ( c . ComponentConfig . Generic . MinResyncPeriod . Nanoseconds ( ) ) * factor )
}
}
// Config return a cloud controller manager config objective
2023-08-17 05:15:28 +00:00
func ( o * CloudControllerManagerOptions ) Config ( allControllers [ ] string , disabledByDefaultControllers [ ] string , controllerAliases map [ string ] string , allWebhooks , disabledByDefaultWebhooks [ ] string ) ( * config . Config , error ) {
if err := o . Validate ( allControllers , disabledByDefaultControllers , controllerAliases , allWebhooks , disabledByDefaultWebhooks ) ; err != nil {
2023-05-29 21:03:29 +00:00
return nil , err
}
if err := o . SecureServing . MaybeDefaultWithSelfSignedCerts ( "localhost" , nil , [ ] net . IP { netutils . ParseIPSloppy ( "127.0.0.1" ) } ) ; err != nil {
return nil , fmt . Errorf ( "error creating self-signed certificates: %v" , err )
}
2023-06-01 16:58:10 +00:00
if o . WebhookServing != nil {
if err := o . WebhookServing . MaybeDefaultWithSelfSignedCerts ( "localhost" , nil , [ ] net . IP { netutils . ParseIPSloppy ( "127.0.0.1" ) } ) ; err != nil {
return nil , fmt . Errorf ( "error creating self-signed certificates for webhook: %v" , err )
}
}
2023-05-29 21:03:29 +00:00
c := & config . Config { }
2023-08-17 05:15:28 +00:00
if err := o . ApplyTo ( c , allControllers , disabledByDefaultControllers , controllerAliases , CloudControllerManagerUserAgent ) ; err != nil {
2023-05-29 21:03:29 +00:00
return nil , err
}
return c , nil
}