Skip to content

Commit 49bbe5d

Browse files
committed
fix ClusterCache doesn't pick latest kubeconfig secret proactively
1 parent 4852b67 commit 49bbe5d

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

controllers/clustercache/cluster_accessor.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ type clusterAccessorHealthProbeConfig struct {
154154
// and health checking information (e.g. lastProbeSuccessTimestamp, consecutiveFailures).
155155
// lockedStateLock must be *always* held (via lock or rLock) before accessing this field.
156156
type clusterAccessorLockedState struct {
157+
// kubeconfigResourceVersion is the resource version of the kubeconfig secret.
158+
// This is used to detect if the kubeconfig secret has changed and we need to re-create the connection.
159+
// It is set when the connection is created.
160+
kubeconfigResourceVersion string
161+
157162
// lastConnectionCreationErrorTimestamp is the timestamp when connection creation failed the last time.
158163
lastConnectionCreationErrorTimestamp time.Time
159164

@@ -273,6 +278,12 @@ func (ca *clusterAccessor) Connect(ctx context.Context) (retErr error) {
273278

274279
log.Info("Connected")
275280

281+
kubeconfigSecret, err := ca.getKubeConfigSecret(ctx)
282+
if err != nil {
283+
return err
284+
}
285+
ca.lockedState.kubeconfigResourceVersion = kubeconfigSecret.ResourceVersion
286+
276287
// Only generate the clientCertificatePrivateKey once as there is no need to regenerate it after disconnect/connect.
277288
// Note: This has to be done before setting connection, because otherwise this code wouldn't be re-entrant if the
278289
// private key generation fails because we check Connected above.
@@ -414,6 +425,18 @@ func (ca *clusterAccessor) GetRESTConfig(ctx context.Context) (*rest.Config, err
414425
return ca.lockedState.connection.restConfig, nil
415426
}
416427

428+
func (ca *clusterAccessor) KubeConfigUpdated(ctx context.Context) (bool, error) {
429+
ca.rLock(ctx)
430+
defer ca.rUnlock(ctx)
431+
432+
kubeconfigSecret, err := ca.getKubeConfigSecret(ctx)
433+
if err != nil {
434+
return false, err
435+
}
436+
437+
return kubeconfigSecret.ResourceVersion != ca.lockedState.kubeconfigResourceVersion, nil
438+
}
439+
417440
func (ca *clusterAccessor) GetClientCertificatePrivateKey(ctx context.Context) *rsa.PrivateKey {
418441
ca.rLock(ctx)
419442
defer ca.rUnlock(ctx)

controllers/clustercache/cluster_accessor_client.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"github.com/pkg/errors"
2727
corev1 "k8s.io/api/core/v1"
28+
v1 "k8s.io/api/core/v1"
2829
apierrors "k8s.io/apimachinery/pkg/api/errors"
2930
"k8s.io/apimachinery/pkg/api/meta"
3031
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -39,6 +40,7 @@ import (
3940
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
4041

4142
kcfg "sigs.k8s.io/cluster-api/util/kubeconfig"
43+
"sigs.k8s.io/cluster-api/util/secret"
4244
)
4345

4446
type createConnectionResult struct {
@@ -48,6 +50,14 @@ type createConnectionResult struct {
4850
Cache *stoppableCache
4951
}
5052

53+
func (ca *clusterAccessor) getKubeConfigSecret(ctx context.Context) (*v1.Secret, error) {
54+
kubeconfigSecret, err := secret.Get(ctx, ca.config.SecretClient, ca.cluster, secret.Kubeconfig)
55+
if err != nil {
56+
return nil, errors.Wrapf(err, "error getting kubeconfig secret")
57+
}
58+
return kubeconfigSecret, nil
59+
}
60+
5161
func (ca *clusterAccessor) createConnection(ctx context.Context) (*createConnectionResult, error) {
5262
log := ctrl.LoggerFrom(ctx)
5363
log.V(6).Info("Creating connection")

controllers/clustercache/cluster_cache.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,20 @@ func (cc *clusterCache) Reconcile(ctx context.Context, req reconcile.Request) (r
448448

449449
requeueAfterDurations := []time.Duration{}
450450

451+
kubeconfigUpdated, err := accessor.KubeConfigUpdated(ctx)
452+
if err != nil {
453+
return reconcile.Result{}, errors.Wrapf(err, "error checking if kubeconfig was updated for cluster %s/%s", clusterKey.Namespace, clusterKey.Name)
454+
}
455+
451456
// Try to connect, if not connected.
452457
connected := accessor.Connected(ctx)
458+
if connected && kubeconfigUpdated {
459+
log.Info("Kubeconfig was updated, disconnecting to re-connect with the new kubeconfig")
460+
accessor.Disconnect(ctx)
461+
didDisconnect = true
462+
connected = false
463+
}
464+
453465
if !connected {
454466
lastConnectionCreationErrorTimestamp := accessor.GetLastConnectionCreationErrorTimestamp(ctx)
455467

0 commit comments

Comments
 (0)