@@ -1442,6 +1442,155 @@ func TestBootstrapTokenRotationMachinePool(t *testing.T) {
14421442 g .Expect (foundNew ).To (BeTrue ())
14431443}
14441444
1445+ func TestBootstrapTokenRefreshIfTokenSecretCleaned (t * testing.T ) {
1446+ t .Run ("should not recreate the token for Machines" , func (t * testing.T ) {
1447+ g := NewWithT (t )
1448+
1449+ cluster := builder .Cluster (metav1 .NamespaceDefault , "cluster" ).Build ()
1450+ cluster .Status .InfrastructureReady = true
1451+ conditions .MarkTrue (cluster , clusterv1 .ControlPlaneInitializedCondition )
1452+ cluster .Spec .ControlPlaneEndpoint = clusterv1.APIEndpoint {Host : "100.105.150.1" , Port : 6443 }
1453+
1454+ controlPlaneInitMachine := newControlPlaneMachine (cluster , "control-plane-init-machine" )
1455+ initConfig := newControlPlaneInitKubeadmConfig (controlPlaneInitMachine .Namespace , "control-plane-init-config" )
1456+
1457+ addKubeadmConfigToMachine (initConfig , controlPlaneInitMachine )
1458+
1459+ workerMachine := newWorkerMachineForCluster (cluster )
1460+ workerJoinConfig := newWorkerJoinKubeadmConfig (metav1 .NamespaceDefault , "worker-join-cfg" )
1461+ addKubeadmConfigToMachine (workerJoinConfig , workerMachine )
1462+ objects := []client.Object {
1463+ cluster ,
1464+ workerMachine ,
1465+ workerJoinConfig ,
1466+ }
1467+
1468+ objects = append (objects , createSecrets (t , cluster , initConfig )... )
1469+ myclient := fake .NewClientBuilder ().WithObjects (objects ... ).WithStatusSubresource (& bootstrapv1.KubeadmConfig {}).Build ()
1470+ remoteClient := fake .NewClientBuilder ().Build ()
1471+ k := & KubeadmConfigReconciler {
1472+ Client : myclient ,
1473+ SecretCachingClient : myclient ,
1474+ KubeadmInitLock : & myInitLocker {},
1475+ TokenTTL : DefaultTokenTTL ,
1476+ ClusterCache : clustercache .NewFakeClusterCache (remoteClient , client.ObjectKey {Name : cluster .Name , Namespace : cluster .Namespace }),
1477+ }
1478+ request := ctrl.Request {
1479+ NamespacedName : client.ObjectKey {
1480+ Namespace : metav1 .NamespaceDefault ,
1481+ Name : "worker-join-cfg" ,
1482+ },
1483+ }
1484+ result , err := k .Reconcile (ctx , request )
1485+ g .Expect (err ).ToNot (HaveOccurred ())
1486+ g .Expect (result .RequeueAfter ).To (Equal (k .TokenTTL / 3 ))
1487+
1488+ cfg , err := getKubeadmConfig (myclient , "worker-join-cfg" , metav1 .NamespaceDefault )
1489+ g .Expect (err ).ToNot (HaveOccurred ())
1490+ g .Expect (cfg .Status .Ready ).To (BeTrue ())
1491+ g .Expect (cfg .Status .DataSecretName ).NotTo (BeNil ())
1492+ g .Expect (cfg .Status .ObservedGeneration ).NotTo (BeNil ())
1493+ g .Expect (cfg .Spec .JoinConfiguration .Discovery .BootstrapToken .Token ).ToNot (BeEmpty ())
1494+ firstToken := cfg .Spec .JoinConfiguration .Discovery .BootstrapToken .Token
1495+
1496+ l := & corev1.SecretList {}
1497+ g .Expect (remoteClient .List (ctx , l , client .ListOption (client .InNamespace (metav1 .NamespaceSystem )))).To (Succeed ())
1498+ g .Expect (l .Items ).To (HaveLen (1 ))
1499+
1500+ t .Log ("Token should not get recreated for single Machine since it will not use the new token if spec.bootstrap.dataSecretName was already set" )
1501+
1502+ // Simulate token cleaner of Kubernetes having deleted the token secret
1503+ err = remoteClient .Delete (ctx , & l .Items [0 ])
1504+ g .Expect (err ).ToNot (HaveOccurred ())
1505+
1506+ result , err = k .Reconcile (ctx , request )
1507+ g .Expect (err ).To (HaveOccurred ())
1508+ g .Expect (err .Error ()).To (ContainSubstring ("failed to get bootstrap token secret in order to refresh it" ))
1509+ // New token should not have been created
1510+ cfg , err = getKubeadmConfig (myclient , "worker-join-cfg" , metav1 .NamespaceDefault )
1511+ g .Expect (err ).ToNot (HaveOccurred ())
1512+ g .Expect (cfg .Spec .JoinConfiguration .Discovery .BootstrapToken .Token ).To (Equal (firstToken ))
1513+
1514+ l = & corev1.SecretList {}
1515+ g .Expect (remoteClient .List (ctx , l , client .ListOption (client .InNamespace (metav1 .NamespaceSystem )))).To (Succeed ())
1516+ g .Expect (l .Items ).To (BeEmpty ())
1517+ })
1518+ t .Run ("should recreate the token for MachinePools" , func (t * testing.T ) {
1519+ _ = feature .MutableGates .Set ("MachinePool=true" )
1520+ g := NewWithT (t )
1521+
1522+ cluster := builder .Cluster (metav1 .NamespaceDefault , "cluster" ).Build ()
1523+ cluster .Status .InfrastructureReady = true
1524+ conditions .MarkTrue (cluster , clusterv1 .ControlPlaneInitializedCondition )
1525+ cluster .Spec .ControlPlaneEndpoint = clusterv1.APIEndpoint {Host : "100.105.150.1" , Port : 6443 }
1526+
1527+ controlPlaneInitMachine := newControlPlaneMachine (cluster , "control-plane-init-machine" )
1528+ initConfig := newControlPlaneInitKubeadmConfig (controlPlaneInitMachine .Namespace , "control-plane-init-config" )
1529+
1530+ addKubeadmConfigToMachine (initConfig , controlPlaneInitMachine )
1531+
1532+ workerMachinePool := newWorkerMachinePoolForCluster (cluster )
1533+ workerJoinConfig := newWorkerJoinKubeadmConfig (workerMachinePool .Namespace , "workerpool-join-cfg" )
1534+ addKubeadmConfigToMachinePool (workerJoinConfig , workerMachinePool )
1535+ objects := []client.Object {
1536+ cluster ,
1537+ workerMachinePool ,
1538+ workerJoinConfig ,
1539+ }
1540+
1541+ objects = append (objects , createSecrets (t , cluster , initConfig )... )
1542+ myclient := fake .NewClientBuilder ().WithObjects (objects ... ).WithStatusSubresource (& bootstrapv1.KubeadmConfig {}, & expv1.MachinePool {}).Build ()
1543+ remoteClient := fake .NewClientBuilder ().Build ()
1544+ k := & KubeadmConfigReconciler {
1545+ Client : myclient ,
1546+ SecretCachingClient : myclient ,
1547+ KubeadmInitLock : & myInitLocker {},
1548+ TokenTTL : DefaultTokenTTL ,
1549+ ClusterCache : clustercache .NewFakeClusterCache (remoteClient , client.ObjectKey {Name : cluster .Name , Namespace : cluster .Namespace }),
1550+ }
1551+ request := ctrl.Request {
1552+ NamespacedName : client.ObjectKey {
1553+ Namespace : metav1 .NamespaceDefault ,
1554+ Name : "workerpool-join-cfg" ,
1555+ },
1556+ }
1557+ result , err := k .Reconcile (ctx , request )
1558+ g .Expect (err ).ToNot (HaveOccurred ())
1559+ g .Expect (result .RequeueAfter ).To (Equal (k .TokenTTL / 3 ))
1560+
1561+ cfg , err := getKubeadmConfig (myclient , "workerpool-join-cfg" , metav1 .NamespaceDefault )
1562+ g .Expect (err ).ToNot (HaveOccurred ())
1563+ g .Expect (cfg .Status .Ready ).To (BeTrue ())
1564+ g .Expect (cfg .Status .DataSecretName ).NotTo (BeNil ())
1565+ g .Expect (cfg .Status .ObservedGeneration ).NotTo (BeNil ())
1566+ g .Expect (cfg .Spec .JoinConfiguration .Discovery .BootstrapToken .Token ).ToNot (BeEmpty ())
1567+ firstToken := cfg .Spec .JoinConfiguration .Discovery .BootstrapToken .Token
1568+
1569+ l := & corev1.SecretList {}
1570+ g .Expect (remoteClient .List (ctx , l , client .ListOption (client .InNamespace (metav1 .NamespaceSystem )))).To (Succeed ())
1571+ g .Expect (l .Items ).To (HaveLen (1 ))
1572+
1573+ t .Log ("Ensure that the token gets recreated if it was cleaned up by Kubernetes (e.g. on expiry)" )
1574+
1575+ // Simulate token cleaner of Kubernetes having deleted the token secret
1576+ err = remoteClient .Delete (ctx , & l .Items [0 ])
1577+ g .Expect (err ).ToNot (HaveOccurred ())
1578+
1579+ result , err = k .Reconcile (ctx , request )
1580+ g .Expect (err ).ToNot (HaveOccurred ())
1581+ g .Expect (result .RequeueAfter ).To (Equal (k .TokenTTL / 3 ))
1582+ // New token should have been created
1583+ cfg , err = getKubeadmConfig (myclient , "workerpool-join-cfg" , metav1 .NamespaceDefault )
1584+ g .Expect (err ).ToNot (HaveOccurred ())
1585+ g .Expect (cfg .Spec .JoinConfiguration .Discovery .BootstrapToken .Token ).ToNot (BeEmpty ())
1586+ g .Expect (cfg .Spec .JoinConfiguration .Discovery .BootstrapToken .Token ).ToNot (Equal (firstToken ))
1587+
1588+ l = & corev1.SecretList {}
1589+ g .Expect (remoteClient .List (ctx , l , client .ListOption (client .InNamespace (metav1 .NamespaceSystem )))).To (Succeed ())
1590+ g .Expect (l .Items ).To (HaveLen (1 ))
1591+ })
1592+ }
1593+
14451594// Ensure the discovery portion of the JoinConfiguration gets generated correctly.
14461595func TestKubeadmConfigReconciler_Reconcile_DiscoveryReconcileBehaviors (t * testing.T ) {
14471596 caHash := []string {"...." }
0 commit comments