@@ -781,3 +781,62 @@ func getCounterMetric(metricFamilyName, controllerName string) (float64, error)
781
781
782
782
return 0 , fmt .Errorf ("failed to find %q metric" , metricFamilyName )
783
783
}
784
+
785
+ func TestReconcile_KubeconfigSecretResourceVersionChange (t * testing.T ) {
786
+ g := NewWithT (t )
787
+ ctx := context .Background ()
788
+
789
+ testCluster := & clusterv1.Cluster {
790
+ ObjectMeta : metav1.ObjectMeta {
791
+ Name : "test-kubeconfig-rv" ,
792
+ Namespace : metav1 .NamespaceDefault ,
793
+ },
794
+ }
795
+ clusterKey := client .ObjectKeyFromObject (testCluster )
796
+ g .Expect (env .CreateAndWait (ctx , testCluster )).To (Succeed ())
797
+ defer func () { g .Expect (client .IgnoreNotFound (env .CleanupAndWait (ctx , testCluster ))).To (Succeed ()) }()
798
+
799
+ opts := Options {
800
+ SecretClient : env .GetClient (),
801
+ Client : ClientOptions {
802
+ UserAgent : remote .DefaultClusterAPIUserAgent ("test-controller-manager" ),
803
+ Timeout : 10 * time .Second ,
804
+ },
805
+ Cache : CacheOptions {
806
+ Indexes : []CacheOptionsIndex {NodeProviderIDIndex },
807
+ },
808
+ }
809
+ accessorConfig := buildClusterAccessorConfig (env .GetScheme (), opts , nil )
810
+ cc := & clusterCache {
811
+ client : env .GetAPIReader (),
812
+ clusterAccessorConfig : accessorConfig ,
813
+ clusterAccessors : make (map [client.ObjectKey ]* clusterAccessor ),
814
+ cacheCtx : context .Background (),
815
+ }
816
+
817
+ // Set Cluster.Status.InfrastructureReady == true
818
+ patch := client .MergeFrom (testCluster .DeepCopy ())
819
+ testCluster .Status .Initialization = & clusterv1.ClusterInitializationStatus {InfrastructureProvisioned : true }
820
+ g .Expect (env .Status ().Patch (ctx , testCluster , patch )).To (Succeed ())
821
+
822
+ // Create kubeconfig Secret
823
+ kubeconfigSecret := kubeconfig .GenerateSecret (testCluster , kubeconfig .FromEnvTestConfig (env .Config , testCluster ))
824
+ g .Expect (env .CreateAndWait (ctx , kubeconfigSecret )).To (Succeed ())
825
+ defer func () { g .Expect (env .CleanupAndWait (ctx , kubeconfigSecret )).To (Succeed ()) }()
826
+
827
+ // Initial reconcile to connect
828
+ res , err := cc .Reconcile (ctx , reconcile.Request {NamespacedName : clusterKey })
829
+ g .Expect (err ).ToNot (HaveOccurred ())
830
+ g .Expect (res .RequeueAfter ).To (BeNumerically (">=" , accessorConfig .HealthProbe .Interval - 2 * time .Second ))
831
+ g .Expect (cc .getClusterAccessor (clusterKey ).Connected (ctx )).To (BeTrue ())
832
+
833
+ // Simulate kubeconfig Secret update (resourceVersion change)
834
+ kubeconfigSecret .Data ["dummy" ] = []byte ("changed" )
835
+ g .Expect (env .Update (ctx , kubeconfigSecret )).To (Succeed ())
836
+
837
+ // Reconcile again, should detect update and disconnect
838
+ _ = cc .getClusterAccessor (clusterKey ) // ensure accessor is present
839
+ res , err = cc .Reconcile (ctx , reconcile.Request {NamespacedName : clusterKey })
840
+ g .Expect (err ).ToNot (HaveOccurred ())
841
+ g .Expect (cc .getClusterAccessor (clusterKey ).Connected (ctx )).To (BeFalse ())
842
+ }
0 commit comments