Skip to content

Commit 81f6e18

Browse files
authored
Merge pull request #202 from DerekFrank/common-flags
Adding a package to contain common sidecar flags
2 parents edbdcce + ff335e3 commit 81f6e18

28 files changed

+4915
-1
lines changed

config/config.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package config
17+
18+
import (
19+
"github.com/kubernetes-csi/csi-lib-utils/standardflags"
20+
"k8s.io/client-go/rest"
21+
"k8s.io/client-go/tools/clientcmd"
22+
)
23+
24+
func BuildConfig(kubeconfig string, opts standardflags.SidecarConfiguration) (*rest.Config, error) {
25+
config, err := buildConfig(kubeconfig)
26+
if err != nil {
27+
return config, err
28+
}
29+
config.QPS = float32(opts.KubeAPIQPS)
30+
config.Burst = opts.KubeAPIBurst
31+
return config, nil
32+
}
33+
34+
func buildConfig(kubeconfig string) (*rest.Config, error) {
35+
if kubeconfig != "" {
36+
return clientcmd.BuildConfigFromFlags("", kubeconfig)
37+
}
38+
return rest.InClusterConfig()
39+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/kubernetes-csi/csi-lib-utils
22

3-
go 1.24.0
3+
go 1.24.6
44

55
require (
66
github.com/container-storage-interface/spec v1.11.0

leaderelection/leader_election.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ import (
2525
"strings"
2626
"time"
2727

28+
"github.com/kubernetes-csi/csi-lib-utils/standardflags"
2829
v1 "k8s.io/api/core/v1"
2930
"k8s.io/client-go/kubernetes"
3031
"k8s.io/client-go/kubernetes/scheme"
3132
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
33+
"k8s.io/client-go/rest"
3234
"k8s.io/client-go/tools/leaderelection"
3335
"k8s.io/client-go/tools/leaderelection/resourcelock"
3436
"k8s.io/client-go/tools/record"
@@ -215,6 +217,58 @@ func (l *leaderElection) Run() error {
215217
return nil // should never reach here
216218
}
217219

220+
func RunWithLeaderElection(
221+
ctx context.Context,
222+
config *rest.Config,
223+
opts standardflags.SidecarConfiguration,
224+
run func(context.Context),
225+
driverName string,
226+
mux *http.ServeMux,
227+
releaseOnExit bool) {
228+
229+
logger := klog.FromContext(ctx)
230+
231+
if !opts.LeaderElection {
232+
run(ctx)
233+
} else {
234+
// Create a new clientset for leader election. When the attacher
235+
// gets busy and its client gets throttled, the leader election
236+
// can proceed without issues.
237+
leClientset, err := kubernetes.NewForConfig(config)
238+
if err != nil {
239+
logger.Error(err, "Failed to create leaderelection client")
240+
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
241+
}
242+
243+
// Name of config map with leader election lock
244+
le := NewLeaderElection(leClientset, driverName, run)
245+
if opts.HttpEndpoint != "" {
246+
le.PrepareHealthCheck(mux, DefaultHealthCheckTimeout)
247+
}
248+
249+
if opts.LeaderElectionNamespace != "" {
250+
le.WithNamespace(opts.LeaderElectionNamespace)
251+
}
252+
253+
if opts.LeaderElectionLabels != nil {
254+
le.WithLabels(opts.LeaderElectionLabels)
255+
}
256+
257+
le.WithLeaseDuration(opts.LeaderElectionLeaseDuration)
258+
le.WithRenewDeadline(opts.LeaderElectionRenewDeadline)
259+
le.WithRetryPeriod(opts.LeaderElectionRetryPeriod)
260+
if releaseOnExit {
261+
le.WithReleaseOnCancel(true)
262+
le.WithContext(ctx)
263+
}
264+
265+
if err := le.Run(); err != nil {
266+
logger.Error(err, "Failed to initialize leader election")
267+
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
268+
}
269+
}
270+
}
271+
218272
func defaultLeaderElectionIdentity() (string, error) {
219273
return os.Hostname()
220274
}

standardflags/flags.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package standardflags
18+
19+
import (
20+
"flag"
21+
"fmt"
22+
"strings"
23+
"time"
24+
)
25+
26+
type SidecarConfiguration struct {
27+
ShowVersion bool
28+
29+
KubeConfig string
30+
CSIAddress string
31+
32+
LeaderElection bool
33+
LeaderElectionNamespace string
34+
LeaderElectionLeaseDuration time.Duration
35+
LeaderElectionRenewDeadline time.Duration
36+
LeaderElectionRetryPeriod time.Duration
37+
LeaderElectionLabels stringMap
38+
39+
KubeAPIQPS float64
40+
KubeAPIBurst int
41+
42+
HttpEndpoint string
43+
MetricsAddress string
44+
MetricsPath string
45+
}
46+
47+
var Configuration = SidecarConfiguration{}
48+
49+
func RegisterCommonFlags(flags *flag.FlagSet) {
50+
flags.BoolVar(&Configuration.ShowVersion, "version", false, "Show version.")
51+
flags.StringVar(&Configuration.KubeConfig, "kubeconfig", "", "Absolute path to the kubeconfig file. Required only when running out of cluster.")
52+
flags.StringVar(&Configuration.CSIAddress, "csi-address", "/run/csi/socket", "The gRPC endpoint for Target CSI Volume.")
53+
flags.BoolVar(&Configuration.LeaderElection, "leader-election", false, "Enable leader election.")
54+
flags.StringVar(&Configuration.LeaderElectionNamespace, "leader-election-namespace", "", "Namespace where the leader election resource lives. Defaults to the pod namespace if not set.")
55+
flags.DurationVar(&Configuration.LeaderElectionLeaseDuration, "leader-election-lease-duration", 15*time.Second, "Duration, in seconds, that non-leader candidates will wait to force acquire leadership. Defaults to 15 seconds.")
56+
flags.DurationVar(&Configuration.LeaderElectionRenewDeadline, "leader-election-renew-deadline", 10*time.Second, "Duration, in seconds, that the acting leader will retry refreshing leadership before giving up. Defaults to 10 seconds.")
57+
flags.DurationVar(&Configuration.LeaderElectionRetryPeriod, "leader-election-retry-period", 5*time.Second, "Duration, in seconds, the LeaderElector clients should wait between tries of actions. Defaults to 5 seconds.")
58+
flags.Var(&Configuration.LeaderElectionLabels, "leader-election-labels", "List of labels to add to lease when given replica becomes leader. Formatted as a comma seperated list of key:value labels. Example: 'my-label:my-value,my-second-label:my-second-value'")
59+
flags.Float64Var(&Configuration.KubeAPIQPS, "kube-api-qps", 5, "QPS to use while communicating with the kubernetes apiserver. Defaults to 5.0.")
60+
flags.IntVar(&Configuration.KubeAPIBurst, "kube-api-burst", 10, "Burst to use while communicating with the kubernetes apiserver. Defaults to 10.")
61+
flags.StringVar(&Configuration.HttpEndpoint, "http-endpoint", "", "The TCP network address where the HTTP server for diagnostics, including metrics and leader election health check, will listen (example: `:8080`). The default is empty string, which means the server is disabled. Only one of `--metrics-address` and `--http-endpoint` can be set.")
62+
flags.StringVar(&Configuration.MetricsAddress, "metrics-address", "", "(deprecated) The TCP network address where the prometheus metrics endpoint will listen (example: `:8080`). The default is empty string, which means metrics endpoint is disabled. Only one of `--metrics-address` and `--http-endpoint` can be set.")
63+
flag.StringVar(&Configuration.MetricsPath, "metrics-path", "/metrics", "The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.")
64+
}
65+
66+
type stringMap map[string]string
67+
68+
func (sm *stringMap) String() string {
69+
return fmt.Sprintf("%s", *sm)
70+
}
71+
72+
func (sm *stringMap) Set(value string) error {
73+
outMap := *sm
74+
items := strings.Split(value, ",")
75+
for _, i := range items {
76+
label := strings.Split(i, ":")
77+
if len(label) != 2 {
78+
return fmt.Errorf("malformed item in list of labels: %s", i)
79+
}
80+
outMap[label[0]] = label[1]
81+
}
82+
return nil
83+
}

vendor/k8s.io/client-go/tools/auth/OWNERS

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/k8s.io/client-go/tools/auth/clientauth.go

Lines changed: 125 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)