2323package operator
2424
2525import (
26+ "fmt"
27+ "os"
2628 "time"
2729
30+ "github.com/rs/zerolog"
31+ "k8s.io/api/core/v1"
32+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33+ "k8s.io/apimachinery/pkg/runtime"
2834 "k8s.io/client-go/tools/leaderelection"
2935 "k8s.io/client-go/tools/leaderelection/resourcelock"
36+
37+ "github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
3038)
3139
40+ // runLeaderElection performs a leader election on a lock with given name in
41+ // the namespace that the operator is deployed in.
42+ // When the leader election is won, the given callback is called.
43+ // When the leader election is lost (even after it was won once), the process is killed.
3244func (o * Operator ) runLeaderElection (lockName string , onStart func (stop <- chan struct {})) {
3345 namespace := o .Config .Namespace
3446 kubecli := o .Dependencies .KubeCli
3547 log := o .log .With ().Str ("lock-name" , lockName ).Logger ()
48+ eventTarget := o .getLeaderElectionEventTarget (log )
49+ recordEvent := func (reason , message string ) {
50+ if eventTarget != nil {
51+ o .Dependencies .EventRecorder .Event (eventTarget , v1 .EventTypeNormal , reason , message )
52+ }
53+ }
3654 rl , err := resourcelock .New (resourcelock .EndpointsResourceLock ,
3755 namespace ,
3856 lockName ,
@@ -51,10 +69,49 @@ func (o *Operator) runLeaderElection(lockName string, onStart func(stop <-chan s
5169 RenewDeadline : 10 * time .Second ,
5270 RetryPeriod : 2 * time .Second ,
5371 Callbacks : leaderelection.LeaderCallbacks {
54- OnStartedLeading : onStart ,
72+ OnStartedLeading : func (stop <- chan struct {}) {
73+ recordEvent ("Leader Election Won" , fmt .Sprintf ("Pod %s is running as leader" , o .Config .PodName ))
74+ onStart (stop )
75+ },
5576 OnStoppedLeading : func () {
56- log .Info ().Msg ("Leader election lost" )
77+ recordEvent ("Stop Leading" , fmt .Sprintf ("Pod %s is stopping to run as leader" , o .Config .PodName ))
78+ log .Info ().Msg ("Stop leading. Terminating process" )
79+ os .Exit (1 )
5780 },
5881 },
5982 })
6083}
84+
85+ // getLeaderElectionEventTarget returns the object that leader election related
86+ // events will be added to.
87+ func (o * Operator ) getLeaderElectionEventTarget (log zerolog.Logger ) runtime.Object {
88+ ns := o .Config .Namespace
89+ kubecli := o .Dependencies .KubeCli
90+ pods := kubecli .CoreV1 ().Pods (ns )
91+ log = log .With ().Str ("pod-name" , o .Config .PodName ).Logger ()
92+ pod , err := pods .Get (o .Config .PodName , metav1.GetOptions {})
93+ if err != nil {
94+ log .Error ().Err (err ).Msg ("Cannot find Pod containing this operator" )
95+ return nil
96+ }
97+ rSet , err := k8sutil .GetPodOwner (kubecli , pod , ns )
98+ if err != nil {
99+ log .Error ().Err (err ).Msg ("Cannot find ReplicaSet owning the Pod containing this operator" )
100+ return pod
101+ }
102+ if rSet == nil {
103+ log .Error ().Msg ("Pod containing this operator has no ReplicaSet owner" )
104+ return pod
105+ }
106+ log = log .With ().Str ("replicaSet-name" , rSet .Name ).Logger ()
107+ depl , err := k8sutil .GetReplicaSetOwner (kubecli , rSet , ns )
108+ if err != nil {
109+ log .Error ().Err (err ).Msg ("Cannot find Deployment owning the ReplicataSet that owns the Pod containing this operator" )
110+ return rSet
111+ }
112+ if rSet == nil {
113+ log .Error ().Msg ("ReplicaSet that owns the Pod containing this operator has no Deployment owner" )
114+ return rSet
115+ }
116+ return depl
117+ }
0 commit comments