diff --git a/pkg/client/apiutil/apimachinery.go b/pkg/client/apiutil/apimachinery.go index cf775c3dc8..4612551651 100644 --- a/pkg/client/apiutil/apimachinery.go +++ b/pkg/client/apiutil/apimachinery.go @@ -36,6 +36,9 @@ import ( func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) { // Get a mapper dc := discovery.NewDiscoveryClientForConfigOrDie(c) + + // TODO(mszostok): here we have useful info about all supported groups and resource + // in api-server gr, err := restmapper.GetAPIGroupResources(dc) if err != nil { return nil, err diff --git a/pkg/leaderelection/leader_election.go b/pkg/leaderelection/leader_election.go index b3003ea5e3..59856f863f 100644 --- a/pkg/leaderelection/leader_election.go +++ b/pkg/leaderelection/leader_election.go @@ -43,6 +43,10 @@ type Options struct { // LeaderElectionID determines the name of the configmap that leader election // will use for holding the leader lock. LeaderElectionID string + + // LeaderElectionLockType determines leader election lock type for holding + // the leader lock information. + LeaderElectionLockType LockType } // NewResourceLock creates a new config map resource lock for use in a leader @@ -80,7 +84,7 @@ func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, op } // TODO(JoelSpeed): switch to leaderelection object in 1.12 - return resourcelock.New(resourcelock.ConfigMapsResourceLock, + return resourcelock.New(string(options.LeaderElectionLockType), options.LeaderElectionNamespace, options.LeaderElectionID, client.CoreV1(), diff --git a/pkg/leaderelection/leader_lock_types.go b/pkg/leaderelection/leader_lock_types.go new file mode 100644 index 0000000000..e527b1a4ce --- /dev/null +++ b/pkg/leaderelection/leader_lock_types.go @@ -0,0 +1,35 @@ +package leaderelection + +import ( + "fmt" + + coordinationv1 "k8s.io/api/coordination/v1" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type LockType string + +const ( + ConfigMapsResourceLock LockType = "configmaps" + LeasesResourceLock = "leases" + EndpointsResourceLock = "endpoints" +) + +// GetPreferredLockType chooses the Lease lock if `lease.coordination.k8s.io` is available. +// Otherwise, the ConfigMap resource lock is used. +func GetPreferredLockType(mapper meta.RESTMapper) (LockType, error) { + // check if new leader election api is available + _, err := mapper.RESTMapping(schema.GroupKind{ + Kind: "Lease", + Group: coordinationv1.GroupName, + }) + switch { + case err == nil: + return LeasesResourceLock, nil + case meta.IsNoMatchError(err): + return ConfigMapsResourceLock, nil + default: + return "", fmt.Errorf("unable to retrieve supported server groups: %v", err) + } +} diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 2d045fa91d..338d281a9f 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -118,6 +118,10 @@ type Options struct { // will use for holding the leader lock. LeaderElectionID string + // LeaderElectionLockType determines leader election lock type for holding + // the leader lock information. + LeaderElectionLockType leaderelection.LockType + // LeaseDuration is the duration that non-leader candidates will // wait to force acquire leadership. This is measured against time of // last observed ack. Default is 15 seconds. @@ -245,10 +249,19 @@ func New(config *rest.Config, options Options) (Manager, error) { } // Create the resource lock to enable leader election) + if options.LeaderElectionLockType == "" { // this should be moved somehow into `setOptionsDefaults` func + lockType, err := leaderelection.GetPreferredLockType(mapper) + if err != nil { + return nil, err + } + options.LeaderElectionLockType = lockType + } + resourceLock, err := options.newResourceLock(config, recorderProvider, leaderelection.Options{ LeaderElection: options.LeaderElection, LeaderElectionID: options.LeaderElectionID, LeaderElectionNamespace: options.LeaderElectionNamespace, + LeaderElectionLockType: options.LeaderElectionLockType, }) if err != nil { return nil, err