...
1
16
17 package main
18
19 import (
20 "context"
21 "flag"
22 "os"
23 "os/signal"
24 "syscall"
25 "time"
26
27 "github.com/google/uuid"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 clientset "k8s.io/client-go/kubernetes"
30 "k8s.io/client-go/rest"
31 "k8s.io/client-go/tools/clientcmd"
32 "k8s.io/client-go/tools/leaderelection"
33 "k8s.io/client-go/tools/leaderelection/resourcelock"
34 "k8s.io/klog/v2"
35 )
36
37 func buildConfig(kubeconfig string) (*rest.Config, error) {
38 if kubeconfig != "" {
39 cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
40 if err != nil {
41 return nil, err
42 }
43 return cfg, nil
44 }
45
46 cfg, err := rest.InClusterConfig()
47 if err != nil {
48 return nil, err
49 }
50 return cfg, nil
51 }
52
53 func main() {
54 klog.InitFlags(nil)
55
56 var kubeconfig string
57 var leaseLockName string
58 var leaseLockNamespace string
59 var id string
60
61 flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file")
62 flag.StringVar(&id, "id", uuid.New().String(), "the holder identity name")
63 flag.StringVar(&leaseLockName, "lease-lock-name", "", "the lease lock resource name")
64 flag.StringVar(&leaseLockNamespace, "lease-lock-namespace", "", "the lease lock resource namespace")
65 flag.Parse()
66
67 if leaseLockName == "" {
68 klog.Fatal("unable to get lease lock resource name (missing lease-lock-name flag).")
69 }
70 if leaseLockNamespace == "" {
71 klog.Fatal("unable to get lease lock resource namespace (missing lease-lock-namespace flag).")
72 }
73
74
75
76
77
78
79 config, err := buildConfig(kubeconfig)
80 if err != nil {
81 klog.Fatal(err)
82 }
83 client := clientset.NewForConfigOrDie(config)
84
85 run := func(ctx context.Context) {
86
87 klog.Info("Controller loop...")
88
89 select {}
90 }
91
92
93
94 ctx, cancel := context.WithCancel(context.Background())
95 defer cancel()
96
97
98
99
100 ch := make(chan os.Signal, 1)
101 signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
102 go func() {
103 <-ch
104 klog.Info("Received termination, signaling shutdown")
105 cancel()
106 }()
107
108
109
110 lock := &resourcelock.LeaseLock{
111 LeaseMeta: metav1.ObjectMeta{
112 Name: leaseLockName,
113 Namespace: leaseLockNamespace,
114 },
115 Client: client.CoordinationV1(),
116 LockConfig: resourcelock.ResourceLockConfig{
117 Identity: id,
118 },
119 }
120
121
122 leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
123 Lock: lock,
124
125
126
127
128
129
130 ReleaseOnCancel: true,
131 LeaseDuration: 60 * time.Second,
132 RenewDeadline: 15 * time.Second,
133 RetryPeriod: 5 * time.Second,
134 Callbacks: leaderelection.LeaderCallbacks{
135 OnStartedLeading: func(ctx context.Context) {
136
137
138 run(ctx)
139 },
140 OnStoppedLeading: func() {
141
142 klog.Infof("leader lost: %s", id)
143 os.Exit(0)
144 },
145 OnNewLeader: func(identity string) {
146
147 if identity == id {
148
149 return
150 }
151 klog.Infof("new leader elected: %s", identity)
152 },
153 },
154 })
155 }
156
View as plain text