2018-01-09 18:57:14 +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 app
import (
2018-11-26 18:23:56 +00:00
"context"
2018-03-06 22:33:18 +00:00
"fmt"
2018-01-09 18:57:14 +00:00
"net"
"os"
"strings"
"time"
2018-03-06 22:33:18 +00:00
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/uuid"
2018-01-09 18:57:14 +00:00
"k8s.io/apimachinery/pkg/util/wait"
2018-11-26 18:23:56 +00:00
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/healthz"
apiserverflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/apiserver/pkg/util/globalflag"
2018-01-09 18:57:14 +00:00
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
2018-11-26 18:23:56 +00:00
cloudprovider "k8s.io/cloud-provider"
"k8s.io/klog"
2018-03-06 22:33:18 +00:00
cloudcontrollerconfig "k8s.io/kubernetes/cmd/cloud-controller-manager/app/config"
2018-01-09 18:57:14 +00:00
"k8s.io/kubernetes/cmd/cloud-controller-manager/app/options"
2018-03-06 22:33:18 +00:00
genericcontrollermanager "k8s.io/kubernetes/cmd/controller-manager/app"
2018-11-26 18:23:56 +00:00
cmoptions "k8s.io/kubernetes/cmd/controller-manager/app/options"
2018-01-09 18:57:14 +00:00
cloudcontrollers "k8s.io/kubernetes/pkg/controller/cloud"
routecontroller "k8s.io/kubernetes/pkg/controller/route"
servicecontroller "k8s.io/kubernetes/pkg/controller/service"
"k8s.io/kubernetes/pkg/util/configz"
2018-03-06 22:33:18 +00:00
utilflag "k8s.io/kubernetes/pkg/util/flag"
2018-11-26 18:23:56 +00:00
"k8s.io/kubernetes/pkg/version"
2018-03-06 22:33:18 +00:00
"k8s.io/kubernetes/pkg/version/verflag"
2018-01-09 18:57:14 +00:00
)
const (
// ControllerStartJitter is the jitter value used when starting controller managers.
ControllerStartJitter = 1.0
2018-11-26 18:23:56 +00:00
// ConfigzName is the name used for register cloud-controller manager /configz, same with GroupName.
ConfigzName = "cloudcontrollermanager.config.k8s.io"
2018-01-09 18:57:14 +00:00
)
// NewCloudControllerManagerCommand creates a *cobra.Command object with default parameters
func NewCloudControllerManagerCommand ( ) * cobra . Command {
2018-07-18 14:47:22 +00:00
s , err := options . NewCloudControllerManagerOptions ( )
if err != nil {
2018-11-26 18:23:56 +00:00
klog . Fatalf ( "unable to initialize command options: %v" , err )
2018-07-18 14:47:22 +00:00
}
2018-01-09 18:57:14 +00:00
cmd := & cobra . Command {
Use : "cloud-controller-manager" ,
Long : ` The Cloud controller manager is a daemon that embeds
the cloud specific control loops shipped with Kubernetes . ` ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
2018-03-06 22:33:18 +00:00
verflag . PrintAndExitIfRequested ( )
utilflag . PrintFlags ( cmd . Flags ( ) )
c , err := s . Config ( )
if err != nil {
fmt . Fprintf ( os . Stderr , "%v\n" , err )
os . Exit ( 1 )
}
2018-11-26 18:23:56 +00:00
if err := Run ( c . Complete ( ) , wait . NeverStop ) ; err != nil {
2018-03-06 22:33:18 +00:00
fmt . Fprintf ( os . Stderr , "%v\n" , err )
os . Exit ( 1 )
}
2018-01-09 18:57:14 +00:00
} ,
}
2018-11-26 18:23:56 +00:00
fs := cmd . Flags ( )
namedFlagSets := s . Flags ( )
verflag . AddFlags ( namedFlagSets . FlagSet ( "global" ) )
globalflag . AddGlobalFlags ( namedFlagSets . FlagSet ( "global" ) , cmd . Name ( ) )
cmoptions . AddCustomGlobalFlags ( namedFlagSets . FlagSet ( "generic" ) )
for _ , f := range namedFlagSets . FlagSets {
fs . AddFlagSet ( f )
2018-01-09 18:57:14 +00:00
}
2018-11-26 18:23:56 +00:00
usageFmt := "Usage:\n %s\n"
cols , _ , _ := apiserverflag . TerminalSize ( cmd . OutOrStdout ( ) )
cmd . SetUsageFunc ( func ( cmd * cobra . Command ) error {
fmt . Fprintf ( cmd . OutOrStderr ( ) , usageFmt , cmd . UseLine ( ) )
apiserverflag . PrintSections ( cmd . OutOrStderr ( ) , namedFlagSets , cols )
return nil
} )
cmd . SetHelpFunc ( func ( cmd * cobra . Command , args [ ] string ) {
fmt . Fprintf ( cmd . OutOrStdout ( ) , "%s\n\n" + usageFmt , cmd . Long , cmd . UseLine ( ) )
apiserverflag . PrintSections ( cmd . OutOrStdout ( ) , namedFlagSets , cols )
} )
return cmd
2018-01-09 18:57:14 +00:00
}
// Run runs the ExternalCMServer. This should never exit.
2018-11-26 18:23:56 +00:00
func Run ( c * cloudcontrollerconfig . CompletedConfig , stopCh <- chan struct { } ) error {
// To help debugging, immediately log version
klog . Infof ( "Version: %+v" , version . Get ( ) )
cloud , err := cloudprovider . InitCloudProvider ( c . ComponentConfig . KubeCloudShared . CloudProvider . Name , c . ComponentConfig . KubeCloudShared . CloudProvider . CloudConfigFile )
2018-01-09 18:57:14 +00:00
if err != nil {
2018-11-26 18:23:56 +00:00
klog . Fatalf ( "Cloud provider could not be initialized: %v" , err )
2018-01-09 18:57:14 +00:00
}
2018-03-06 22:33:18 +00:00
if cloud == nil {
2018-11-26 18:23:56 +00:00
klog . Fatalf ( "cloud provider is nil" )
2018-03-06 22:33:18 +00:00
}
2018-01-09 18:57:14 +00:00
if cloud . HasClusterID ( ) == false {
2018-07-18 14:47:22 +00:00
if c . ComponentConfig . KubeCloudShared . AllowUntaggedCloud == true {
2018-11-26 18:23:56 +00:00
klog . Warning ( "detected a cluster without a ClusterID. A ClusterID will be required in the future. Please tag your cluster to avoid any future issues" )
2018-01-09 18:57:14 +00:00
} else {
2018-11-26 18:23:56 +00:00
klog . Fatalf ( "no ClusterID found. A ClusterID is required for the cloud provider to function properly. This check can be bypassed by setting the allow-untagged-cloud option" )
2018-01-09 18:57:14 +00:00
}
}
2018-03-06 22:33:18 +00:00
// setup /configz endpoint
2018-11-26 18:23:56 +00:00
if cz , err := configz . New ( ConfigzName ) ; err == nil {
2018-07-18 14:47:22 +00:00
cz . Set ( c . ComponentConfig )
2018-01-09 18:57:14 +00:00
} else {
2018-11-26 18:23:56 +00:00
klog . Errorf ( "unable to register configz: %c" , err )
}
// Setup any healthz checks we will want to use.
var checks [ ] healthz . HealthzChecker
var electionChecker * leaderelection . HealthzAdaptor
if c . ComponentConfig . Generic . LeaderElection . LeaderElect {
electionChecker = leaderelection . NewLeaderHealthzAdaptor ( time . Second * 20 )
checks = append ( checks , electionChecker )
2018-01-09 18:57:14 +00:00
}
2018-03-06 22:33:18 +00:00
// Start the controller manager HTTP server
2018-07-18 14:47:22 +00:00
if c . SecureServing != nil {
2018-11-26 18:23:56 +00:00
unsecuredMux := genericcontrollermanager . NewBaseHandler ( & c . ComponentConfig . Generic . Debugging , checks ... )
handler := genericcontrollermanager . BuildHandlerChain ( unsecuredMux , & c . Authorization , & c . Authentication )
2018-07-18 14:47:22 +00:00
if err := c . SecureServing . Serve ( handler , 0 , stopCh ) ; err != nil {
2018-03-06 22:33:18 +00:00
return err
}
}
2018-07-18 14:47:22 +00:00
if c . InsecureServing != nil {
2018-11-26 18:23:56 +00:00
unsecuredMux := genericcontrollermanager . NewBaseHandler ( & c . ComponentConfig . Generic . Debugging , checks ... )
insecureSuperuserAuthn := server . AuthenticationInfo { Authenticator : & server . InsecureSuperuser { } }
handler := genericcontrollermanager . BuildHandlerChain ( unsecuredMux , nil , & insecureSuperuserAuthn )
2018-07-18 14:47:22 +00:00
if err := c . InsecureServing . Serve ( handler , 0 , stopCh ) ; err != nil {
2018-03-06 22:33:18 +00:00
return err
}
2018-01-09 18:57:14 +00:00
}
2018-11-26 18:23:56 +00:00
run := func ( ctx context . Context ) {
if err := startControllers ( c , ctx . Done ( ) , cloud ) ; err != nil {
klog . Fatalf ( "error running controllers: %v" , err )
2018-03-06 22:33:18 +00:00
}
2018-01-09 18:57:14 +00:00
}
2018-11-26 18:23:56 +00:00
if ! c . ComponentConfig . Generic . LeaderElection . LeaderElect {
run ( context . TODO ( ) )
2018-01-09 18:57:14 +00:00
panic ( "unreachable" )
}
// Identity used to distinguish between multiple cloud controller manager instances
id , err := os . Hostname ( )
if err != nil {
return err
}
2018-03-06 22:33:18 +00:00
// add a uniquifier so that two processes on the same host don't accidentally both become active
id = id + "_" + string ( uuid . NewUUID ( ) )
2018-01-09 18:57:14 +00:00
// Lock required for leader election
2018-11-26 18:23:56 +00:00
rl , err := resourcelock . New ( c . ComponentConfig . Generic . LeaderElection . ResourceLock ,
2018-01-09 18:57:14 +00:00
"kube-system" ,
"cloud-controller-manager" ,
2018-07-18 14:47:22 +00:00
c . LeaderElectionClient . CoreV1 ( ) ,
2018-01-09 18:57:14 +00:00
resourcelock . ResourceLockConfig {
2018-03-06 22:33:18 +00:00
Identity : id ,
2018-07-18 14:47:22 +00:00
EventRecorder : c . EventRecorder ,
2018-01-09 18:57:14 +00:00
} )
if err != nil {
2018-11-26 18:23:56 +00:00
klog . Fatalf ( "error creating lock: %v" , err )
2018-01-09 18:57:14 +00:00
}
// Try and become the leader and start cloud controller manager loops
2018-11-26 18:23:56 +00:00
leaderelection . RunOrDie ( context . TODO ( ) , leaderelection . LeaderElectionConfig {
2018-01-09 18:57:14 +00:00
Lock : rl ,
2018-11-26 18:23:56 +00:00
LeaseDuration : c . ComponentConfig . Generic . LeaderElection . LeaseDuration . Duration ,
RenewDeadline : c . ComponentConfig . Generic . LeaderElection . RenewDeadline . Duration ,
RetryPeriod : c . ComponentConfig . Generic . LeaderElection . RetryPeriod . Duration ,
2018-01-09 18:57:14 +00:00
Callbacks : leaderelection . LeaderCallbacks {
OnStartedLeading : run ,
OnStoppedLeading : func ( ) {
2018-11-26 18:23:56 +00:00
klog . Fatalf ( "leaderelection lost" )
2018-01-09 18:57:14 +00:00
} ,
} ,
2018-11-26 18:23:56 +00:00
WatchDog : electionChecker ,
Name : "cloud-controller-manager" ,
2018-01-09 18:57:14 +00:00
} )
panic ( "unreachable" )
}
2018-03-06 22:33:18 +00:00
// startControllers starts the cloud specific controller loops.
2018-11-26 18:23:56 +00:00
func startControllers ( c * cloudcontrollerconfig . CompletedConfig , stop <- chan struct { } , cloud cloudprovider . Interface ) error {
2018-01-09 18:57:14 +00:00
// Function to build the kube client object
2018-03-06 22:33:18 +00:00
client := func ( serviceAccountName string ) kubernetes . Interface {
2018-11-26 18:23:56 +00:00
return c . ClientBuilder . ClientOrDie ( serviceAccountName )
2018-01-09 18:57:14 +00:00
}
if cloud != nil {
// Initialize the cloud provider with a reference to the clientBuilder
2018-11-26 18:23:56 +00:00
cloud . Initialize ( c . ClientBuilder , stop )
2018-01-09 18:57:14 +00:00
}
// Start the CloudNodeController
nodeController := cloudcontrollers . NewCloudNodeController (
2018-11-26 18:23:56 +00:00
c . SharedInformers . Core ( ) . V1 ( ) . Nodes ( ) ,
2018-01-09 18:57:14 +00:00
client ( "cloud-node-controller" ) , cloud ,
2018-07-18 14:47:22 +00:00
c . ComponentConfig . KubeCloudShared . NodeMonitorPeriod . Duration ,
c . ComponentConfig . NodeStatusUpdateFrequency . Duration )
2018-01-09 18:57:14 +00:00
2018-07-18 14:47:22 +00:00
nodeController . Run ( stop )
2018-11-26 18:23:56 +00:00
time . Sleep ( wait . Jitter ( c . ComponentConfig . Generic . ControllerStartInterval . Duration , ControllerStartJitter ) )
2018-01-09 18:57:14 +00:00
// Start the PersistentVolumeLabelController
pvlController := cloudcontrollers . NewPersistentVolumeLabelController ( client ( "pvl-controller" ) , cloud )
2018-07-18 14:47:22 +00:00
go pvlController . Run ( 5 , stop )
2018-11-26 18:23:56 +00:00
time . Sleep ( wait . Jitter ( c . ComponentConfig . Generic . ControllerStartInterval . Duration , ControllerStartJitter ) )
2018-01-09 18:57:14 +00:00
// Start the service controller
serviceController , err := servicecontroller . New (
cloud ,
client ( "service-controller" ) ,
2018-11-26 18:23:56 +00:00
c . SharedInformers . Core ( ) . V1 ( ) . Services ( ) ,
c . SharedInformers . Core ( ) . V1 ( ) . Nodes ( ) ,
2018-07-18 14:47:22 +00:00
c . ComponentConfig . KubeCloudShared . ClusterName ,
2018-01-09 18:57:14 +00:00
)
if err != nil {
2018-11-26 18:23:56 +00:00
klog . Errorf ( "Failed to start service controller: %v" , err )
2018-01-09 18:57:14 +00:00
} else {
2018-07-18 14:47:22 +00:00
go serviceController . Run ( stop , int ( c . ComponentConfig . ServiceController . ConcurrentServiceSyncs ) )
2018-11-26 18:23:56 +00:00
time . Sleep ( wait . Jitter ( c . ComponentConfig . Generic . ControllerStartInterval . Duration , ControllerStartJitter ) )
2018-01-09 18:57:14 +00:00
}
// If CIDRs should be allocated for pods and set on the CloudProvider, then start the route controller
2018-07-18 14:47:22 +00:00
if c . ComponentConfig . KubeCloudShared . AllocateNodeCIDRs && c . ComponentConfig . KubeCloudShared . ConfigureCloudRoutes {
2018-01-09 18:57:14 +00:00
if routes , ok := cloud . Routes ( ) ; ! ok {
2018-11-26 18:23:56 +00:00
klog . Warning ( "configure-cloud-routes is set, but cloud provider does not support routes. Will not configure cloud provider routes." )
2018-01-09 18:57:14 +00:00
} else {
var clusterCIDR * net . IPNet
2018-07-18 14:47:22 +00:00
if len ( strings . TrimSpace ( c . ComponentConfig . KubeCloudShared . ClusterCIDR ) ) != 0 {
_ , clusterCIDR , err = net . ParseCIDR ( c . ComponentConfig . KubeCloudShared . ClusterCIDR )
2018-01-09 18:57:14 +00:00
if err != nil {
2018-11-26 18:23:56 +00:00
klog . Warningf ( "Unsuccessful parsing of cluster CIDR %v: %v" , c . ComponentConfig . KubeCloudShared . ClusterCIDR , err )
2018-01-09 18:57:14 +00:00
}
}
2018-11-26 18:23:56 +00:00
routeController := routecontroller . New ( routes , client ( "route-controller" ) , c . SharedInformers . Core ( ) . V1 ( ) . Nodes ( ) , c . ComponentConfig . KubeCloudShared . ClusterName , clusterCIDR )
2018-07-18 14:47:22 +00:00
go routeController . Run ( stop , c . ComponentConfig . KubeCloudShared . RouteReconciliationPeriod . Duration )
2018-11-26 18:23:56 +00:00
time . Sleep ( wait . Jitter ( c . ComponentConfig . Generic . ControllerStartInterval . Duration , ControllerStartJitter ) )
2018-01-09 18:57:14 +00:00
}
} else {
2018-11-26 18:23:56 +00:00
klog . Infof ( "Will not configure cloud provider routes for allocate-node-cidrs: %v, configure-cloud-routes: %v." , c . ComponentConfig . KubeCloudShared . AllocateNodeCIDRs , c . ComponentConfig . KubeCloudShared . ConfigureCloudRoutes )
2018-01-09 18:57:14 +00:00
}
// If apiserver is not running we should wait for some time and fail only then. This is particularly
// important when we start apiserver and controller manager at the same time.
2018-11-26 18:23:56 +00:00
err = genericcontrollermanager . WaitForAPIServer ( c . VersionedClient , 10 * time . Second )
2018-01-09 18:57:14 +00:00
if err != nil {
2018-11-26 18:23:56 +00:00
klog . Fatalf ( "Failed to wait for apiserver being healthy: %v" , err )
2018-01-09 18:57:14 +00:00
}
2018-11-26 18:23:56 +00:00
c . SharedInformers . Start ( stop )
2018-01-09 18:57:14 +00:00
select { }
}