2019-10-15 21:17:17 +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"
2020-08-10 17:43:49 +00:00
"k8s.io/client-go/kubernetes/scheme"
2019-10-15 21:17:17 +00:00
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/record"
2020-12-01 01:06:26 +00:00
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"
2019-10-15 21:17:17 +00:00
cliflag "k8s.io/component-base/cli/flag"
2020-12-01 01:06:26 +00:00
cmoptions "k8s.io/controller-manager/options"
"k8s.io/controller-manager/pkg/clientbuilder"
// add the related feature gates
_ "k8s.io/controller-manager/pkg/features/register"
2019-10-15 21:17:17 +00:00
)
const (
// CloudControllerManagerUserAgent is the userAgent name when starting cloud-controller managers.
CloudControllerManagerUserAgent = "cloud-controller-manager"
// DefaultInsecureCloudControllerManagerPort is the default insecure cloud-controller manager port.
DefaultInsecureCloudControllerManagerPort = 0
)
// CloudControllerManagerOptions is the main context object for the controller manager.
type CloudControllerManagerOptions struct {
Generic * cmoptions . GenericControllerManagerConfigurationOptions
2020-12-01 01:06:26 +00:00
KubeCloudShared * KubeCloudSharedOptions
ServiceController * ServiceControllerOptions
2019-10-15 21:17:17 +00:00
SecureServing * apiserveroptions . SecureServingOptionsWithLoopback
// TODO: remove insecure serving mode
InsecureServing * apiserveroptions . DeprecatedInsecureServingOptionsWithLoopback
Authentication * apiserveroptions . DelegatingAuthenticationOptions
Authorization * apiserveroptions . DelegatingAuthorizationOptions
Master string
Kubeconfig string
// NodeStatusUpdateFrequency is the frequency at which the controller updates nodes' status
NodeStatusUpdateFrequency metav1 . Duration
}
// NewCloudControllerManagerOptions creates a new ExternalCMServer with a default config.
func NewCloudControllerManagerOptions ( ) ( * CloudControllerManagerOptions , error ) {
componentConfig , err := NewDefaultComponentConfig ( DefaultInsecureCloudControllerManagerPort )
if err != nil {
return nil , err
}
s := CloudControllerManagerOptions {
Generic : cmoptions . NewGenericControllerManagerConfigurationOptions ( & componentConfig . Generic ) ,
2020-12-01 01:06:26 +00:00
KubeCloudShared : NewKubeCloudSharedOptions ( & componentConfig . KubeCloudShared ) ,
ServiceController : & ServiceControllerOptions {
2019-10-15 21:17:17 +00:00
ServiceControllerConfiguration : & componentConfig . ServiceController ,
} ,
SecureServing : apiserveroptions . NewSecureServingOptions ( ) . WithLoopback ( ) ,
InsecureServing : ( & apiserveroptions . DeprecatedInsecureServingOptions {
BindAddress : net . ParseIP ( componentConfig . Generic . Address ) ,
BindPort : int ( componentConfig . Generic . Port ) ,
BindNetwork : "tcp" ,
} ) . WithLoopback ( ) ,
Authentication : apiserveroptions . NewDelegatingAuthenticationOptions ( ) ,
Authorization : apiserveroptions . NewDelegatingAuthorizationOptions ( ) ,
NodeStatusUpdateFrequency : componentConfig . NodeStatusUpdateFrequency ,
}
s . Authentication . RemoteKubeConfigFileOptional = true
s . Authorization . RemoteKubeConfigFileOptional = true
s . Authorization . AlwaysAllowPaths = [ ] string { "/healthz" }
// 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"
2020-12-01 01:06:26 +00:00
s . SecureServing . BindPort = cloudprovider . CloudControllerManagerPort
2019-10-15 21:17:17 +00:00
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 ( insecurePort int32 ) ( * 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
}
internal . Generic . Port = insecurePort
return internal , nil
}
// Flags returns flags for a specific APIServer by section name
func ( o * CloudControllerManagerOptions ) Flags ( allControllers , disabledByDefaultControllers [ ] string ) cliflag . NamedFlagSets {
fss := cliflag . NamedFlagSets { }
o . Generic . AddFlags ( & fss , allControllers , disabledByDefaultControllers )
o . KubeCloudShared . AddFlags ( fss . FlagSet ( "generic" ) )
o . ServiceController . AddFlags ( fss . FlagSet ( "service controller" ) )
o . SecureServing . AddFlags ( fss . FlagSet ( "secure serving" ) )
o . InsecureServing . AddUnqualifiedFlags ( fss . FlagSet ( "insecure 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)." )
fs . StringVar ( & o . Kubeconfig , "kubeconfig" , o . Kubeconfig , "Path to kubeconfig file with authorization and master location information." )
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.
2020-12-01 01:06:26 +00:00
func ( o * CloudControllerManagerOptions ) ApplyTo ( c * config . Config , userAgent string ) error {
2019-10-15 21:17:17 +00:00
var err error
if err = o . Generic . ApplyTo ( & c . ComponentConfig . Generic ) ; err != nil {
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
}
if err = o . InsecureServing . ApplyTo ( & c . InsecureServing , & c . LoopbackClientConfig ) ; err != nil {
return err
}
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 . Kubeconfig , err = clientcmd . BuildConfigFromFlags ( o . Master , o . Kubeconfig )
if err != nil {
return err
}
c . Kubeconfig . DisableCompression = true
2019-12-12 01:27:03 +00:00
c . Kubeconfig . ContentConfig . AcceptContentTypes = o . Generic . ClientConnection . AcceptContentTypes
2019-10-15 21:17:17 +00:00
c . Kubeconfig . ContentConfig . ContentType = o . Generic . ClientConnection . ContentType
c . Kubeconfig . QPS = o . Generic . ClientConnection . QPS
c . Kubeconfig . Burst = int ( o . Generic . ClientConnection . Burst )
c . Client , err = clientset . NewForConfig ( restclient . AddUserAgent ( c . Kubeconfig , userAgent ) )
if err != nil {
return err
}
c . LeaderElectionClient = clientset . NewForConfigOrDie ( restclient . AddUserAgent ( c . Kubeconfig , "leader-election" ) )
c . EventRecorder = createRecorder ( c . Client , userAgent )
2020-12-01 01:06:26 +00:00
rootClientBuilder := clientbuilder . SimpleControllerClientBuilder {
2019-10-15 21:17:17 +00:00
ClientConfig : c . Kubeconfig ,
}
if c . ComponentConfig . KubeCloudShared . UseServiceAccountCredentials {
2020-12-01 01:06:26 +00:00
c . ClientBuilder = clientbuilder . SAControllerClientBuilder {
2019-10-15 21:17:17 +00:00
ClientConfig : restclient . AnonymousClientConfig ( c . Kubeconfig ) ,
CoreClient : c . Client . CoreV1 ( ) ,
AuthenticationClient : c . Client . AuthenticationV1 ( ) ,
Namespace : 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 . Generic . Port = int32 ( o . InsecureServing . BindPort )
c . ComponentConfig . Generic . Address = o . InsecureServing . BindAddress . String ( )
c . ComponentConfig . NodeStatusUpdateFrequency = o . NodeStatusUpdateFrequency
return nil
}
// Validate is used to validate config before launching the cloud controller manager
func ( o * CloudControllerManagerOptions ) Validate ( allControllers , disabledByDefaultControllers [ ] string ) error {
errors := [ ] error { }
errors = append ( errors , o . Generic . Validate ( allControllers , disabledByDefaultControllers ) ... )
errors = append ( errors , o . KubeCloudShared . Validate ( ) ... )
errors = append ( errors , o . ServiceController . Validate ( ) ... )
errors = append ( errors , o . SecureServing . Validate ( ) ... )
errors = append ( errors , o . InsecureServing . Validate ( ) ... )
errors = append ( errors , o . Authentication . Validate ( ) ... )
errors = append ( errors , o . Authorization . Validate ( ) ... )
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
2020-12-01 01:06:26 +00:00
func resyncPeriod ( c * config . Config ) func ( ) time . Duration {
2019-10-15 21:17:17 +00:00
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
2020-12-01 01:06:26 +00:00
func ( o * CloudControllerManagerOptions ) Config ( allControllers , disabledByDefaultControllers [ ] string ) ( * config . Config , error ) {
2019-10-15 21:17:17 +00:00
if err := o . Validate ( allControllers , disabledByDefaultControllers ) ; err != nil {
return nil , err
}
if err := o . SecureServing . MaybeDefaultWithSelfSignedCerts ( "localhost" , nil , [ ] net . IP { net . ParseIP ( "127.0.0.1" ) } ) ; err != nil {
return nil , fmt . Errorf ( "error creating self-signed certificates: %v" , err )
}
2020-12-01 01:06:26 +00:00
c := & config . Config { }
2019-10-15 21:17:17 +00:00
if err := o . ApplyTo ( c , CloudControllerManagerUserAgent ) ; err != nil {
return nil , err
}
return c , nil
}
func createRecorder ( kubeClient clientset . Interface , userAgent string ) record . EventRecorder {
eventBroadcaster := record . NewBroadcaster ( )
2020-08-10 17:43:49 +00:00
eventBroadcaster . StartStructuredLogging ( 0 )
2019-10-15 21:17:17 +00:00
eventBroadcaster . StartRecordingToSink ( & v1core . EventSinkImpl { Interface : kubeClient . CoreV1 ( ) . Events ( "" ) } )
2020-08-10 17:43:49 +00:00
return eventBroadcaster . NewRecorder ( scheme . Scheme , v1 . EventSource { Component : userAgent } )
2019-10-15 21:17:17 +00:00
}