Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Copyright 2025 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config

import (
"github.com/kubernetes-csi/csi-lib-utils/standardflags"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

func BuildConfig(kubeconfig string, opts standardflags.SidecarConfiguration) (*rest.Config, error) {
config, err := buildConfig(kubeconfig)
if err != nil {
return config, err
}
config.QPS = float32(opts.KubeAPIQPS)
config.Burst = opts.KubeAPIBurst
return config, nil
}

func buildConfig(kubeconfig string) (*rest.Config, error) {
if kubeconfig != "" {
return clientcmd.BuildConfigFromFlags("", kubeconfig)
}
return rest.InClusterConfig()
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/kubernetes-csi/csi-lib-utils

go 1.24.0
go 1.24.6

require (
github.com/container-storage-interface/spec v1.11.0
Expand Down
54 changes: 54 additions & 0 deletions leaderelection/leader_election.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ import (
"strings"
"time"

"github.com/kubernetes-csi/csi-lib-utils/standardflags"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
"k8s.io/client-go/tools/record"
Expand Down Expand Up @@ -215,6 +217,58 @@ func (l *leaderElection) Run() error {
return nil // should never reach here
}

func RunWithLeaderElection(
ctx context.Context,
config *rest.Config,
opts standardflags.SidecarConfiguration,
run func(context.Context),
driverName string,
mux *http.ServeMux,
releaseOnExit bool) {

logger := klog.FromContext(ctx)

if !opts.LeaderElection {
run(klog.NewContext(context.Background(), logger))
} else {
// Create a new clientset for leader election. When the attacher
// gets busy and its client gets throttled, the leader election
// can proceed without issues.
leClientset, err := kubernetes.NewForConfig(config)
if err != nil {
logger.Error(err, "Failed to create leaderelection client")
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
}

// Name of config map with leader election lock
le := NewLeaderElection(leClientset, driverName, run)
if opts.HttpEndpoint != "" {
le.PrepareHealthCheck(mux, DefaultHealthCheckTimeout)
}

if opts.LeaderElectionNamespace != "" {
le.WithNamespace(opts.LeaderElectionNamespace)
}

if opts.LeaderElectionLabels != nil {
le.WithLabels(opts.LeaderElectionLabels)
}

le.WithLeaseDuration(opts.LeaderElectionLeaseDuration)
le.WithRenewDeadline(opts.LeaderElectionRenewDeadline)
le.WithRetryPeriod(opts.LeaderElectionRetryPeriod)
if releaseOnExit {
le.WithReleaseOnCancel(true)
le.WithContext(ctx)
}

if err := le.Run(); err != nil {
logger.Error(err, "Failed to initialize leader election")
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
}
}
}

func defaultLeaderElectionIdentity() (string, error) {
return os.Hostname()
}
Expand Down
83 changes: 83 additions & 0 deletions standardflags/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
Copyright 2025 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package standardflags

import (
"flag"
"fmt"
"strings"
"time"
)

type SidecarConfiguration struct {
ShowVersion bool

KubeConfig string
CSIAddress string

LeaderElection bool
LeaderElectionNamespace string
LeaderElectionLeaseDuration time.Duration
LeaderElectionRenewDeadline time.Duration
LeaderElectionRetryPeriod time.Duration
LeaderElectionLabels stringMap

KubeAPIQPS float64
KubeAPIBurst int

HttpEndpoint string
MetricsAddress string
MetricsPath string
}

var Configuration = SidecarConfiguration{}

func RegisterCommonFlags(flags *flag.FlagSet) {
flags.BoolVar(&Configuration.ShowVersion, "version", false, "Show version.")
flags.StringVar(&Configuration.KubeConfig, "kubeconfig", "", "Absolute path to the kubeconfig file. Required only when running out of cluster.")
flags.StringVar(&Configuration.CSIAddress, "csi-address", "/run/csi/socket", "The gRPC endpoint for Target CSI Volume.")
flags.BoolVar(&Configuration.LeaderElection, "leader-election", false, "Enable leader election.")
flags.StringVar(&Configuration.LeaderElectionNamespace, "leader-election-namespace", "", "Namespace where the leader election resource lives. Defaults to the pod namespace if not set.")
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.")
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.")
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.")
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'")
flags.Float64Var(&Configuration.KubeAPIQPS, "kube-api-qps", 5, "QPS to use while communicating with the kubernetes apiserver. Defaults to 5.0.")
flags.IntVar(&Configuration.KubeAPIBurst, "kube-api-burst", 10, "Burst to use while communicating with the kubernetes apiserver. Defaults to 10.")
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.")
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.")
flag.StringVar(&Configuration.MetricsPath, "metrics-path", "/metrics", "The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.")
}

type stringMap map[string]string

func (sm *stringMap) String() string {
return fmt.Sprintf("%s", *sm)
}

func (sm *stringMap) Set(value string) error {
outMap := *sm
items := strings.Split(value, ",")
for _, i := range items {
label := strings.Split(i, ":")
if len(label) != 2 {
return fmt.Errorf("malformed item in list of labels: %s", i)
}
outMap[label[0]] = label[1]
}
return nil
}
8 changes: 8 additions & 0 deletions vendor/k8s.io/client-go/tools/auth/OWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

125 changes: 125 additions & 0 deletions vendor/k8s.io/client-go/tools/auth/clientauth.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading