-
Notifications
You must be signed in to change notification settings - Fork 31
Perform leaderelection in GenericPilot #186
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package leaderelection | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"time" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes" | ||
"k8s.io/client-go/tools/leaderelection" | ||
"k8s.io/client-go/tools/leaderelection/resourcelock" | ||
"k8s.io/client-go/tools/record" | ||
) | ||
|
||
const ( | ||
defaultLeaderElectionLeaseDuration = 15 * time.Second | ||
defaultLeaderElectionRenewDeadline = 10 * time.Second | ||
defaultLeaderElectionRetryPeriod = 2 * time.Second | ||
) | ||
|
||
type Interface interface { | ||
Run() error | ||
Leading() bool | ||
} | ||
|
||
type Elector struct { | ||
LockMeta metav1.ObjectMeta | ||
Client kubernetes.Interface | ||
Recorder record.EventRecorder | ||
|
||
leading bool | ||
} | ||
|
||
var _ Interface = &Elector{} | ||
|
||
func (e *Elector) Run() error { | ||
// Identity used to distinguish between multiple controller manager instances | ||
id, err := os.Hostname() | ||
if err != nil { | ||
return fmt.Errorf("error getting hostname: %s", err) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hostname is unique to the Pod running the pilot process, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not 100% sure on this one. Pilot name does make more sense, however if there is a Deployment managing our Pods, and the update strategy is set to rollingUpdate, there are instances where two pods can be running at once (and both would have the same pilot name). Typically hostname is used when using the leader election packages as it should be unique (hence why we use Hostname when performing this same leader election in navigator-controller) |
||
|
||
// Lock required for leader election | ||
rl := resourcelock.ConfigMapLock{ | ||
ConfigMapMeta: e.LockMeta, | ||
Client: e.Client.CoreV1(), | ||
LockConfig: resourcelock.ResourceLockConfig{ | ||
Identity: id + "-external-navigator-controller", | ||
EventRecorder: e.Recorder, | ||
}, | ||
} | ||
|
||
leaderElector, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{ | ||
Lock: &rl, | ||
LeaseDuration: defaultLeaderElectionLeaseDuration, | ||
RenewDeadline: defaultLeaderElectionRenewDeadline, | ||
RetryPeriod: defaultLeaderElectionRetryPeriod, | ||
Callbacks: leaderelection.LeaderCallbacks{ | ||
OnStartedLeading: func(_ <-chan struct{}) { e.startLeading() }, | ||
OnStoppedLeading: e.stopLeading, | ||
}, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
// TODO: detect leader elector crashes | ||
leaderElector.Run() | ||
return nil | ||
} | ||
|
||
func (e *Elector) Leading() bool { | ||
return e.leading | ||
} | ||
|
||
func (e *Elector) startLeading() { | ||
e.leading = true | ||
} | ||
|
||
func (e *Elector) stopLeading() { | ||
e.leading = false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What operations might be performed here?
#97 talks about
excludeShards
, but that seems like something that would be performed by the Pilot that had been selected to leave the cluster by the ES controller.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the ES pilot case, excludeShards will be handled here. I've got some more work locally to actually do this. This needs to be leader elected as it requires updating the ES API with the new list of nodes that should be excluded. We could do it in each individual Pilot and just hope there's no races, but this way is far more concrete.