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"
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"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/klog"
ccmconfig "k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config"
ccmconfigscheme "k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config/scheme"
ccmconfigv1alpha1 "k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config/v1alpha1"
cloudcontrollerconfig "k8s.io/kubernetes/cmd/cloud-controller-manager/app/config"
cmoptions "k8s.io/kubernetes/cmd/controller-manager/app/options"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/master/ports"
// add the kubernetes feature gates
_ "k8s.io/kubernetes/pkg/features"
)
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
KubeCloudShared * cmoptions . KubeCloudSharedOptions
ServiceController * cmoptions . ServiceControllerOptions
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 ) ,
KubeCloudShared : cmoptions . NewKubeCloudSharedOptions ( & componentConfig . KubeCloudShared ) ,
ServiceController : & cmoptions . ServiceControllerOptions {
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"
s . SecureServing . BindPort = ports . 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 ( 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.
func ( o * CloudControllerManagerOptions ) ApplyTo ( c * cloudcontrollerconfig . Config , userAgent string ) error {
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 )
rootClientBuilder := controller . SimpleControllerClientBuilder {
ClientConfig : c . Kubeconfig ,
}
if c . ComponentConfig . KubeCloudShared . UseServiceAccountCredentials {
c . ClientBuilder = controller . SAControllerClientBuilder {
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
func resyncPeriod ( c * cloudcontrollerconfig . 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
func ( o * CloudControllerManagerOptions ) Config ( allControllers , disabledByDefaultControllers [ ] string ) ( * cloudcontrollerconfig . Config , error ) {
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 )
}
c := & cloudcontrollerconfig . Config { }
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 ( )
eventBroadcaster . StartLogging ( klog . Infof )
eventBroadcaster . StartRecordingToSink ( & v1core . EventSinkImpl { Interface : kubeClient . CoreV1 ( ) . Events ( "" ) } )
// TODO: remove dependence on the legacyscheme
return eventBroadcaster . NewRecorder ( legacyscheme . Scheme , v1 . EventSource { Component : userAgent } )
}