@@ -17,14 +17,19 @@ limitations under the License.
1717package controllers
1818
1919import (
20+ "context"
2021 "fmt"
2122 "testing"
2223
2324 "github.com/hetznercloud/hcloud-go/v2/hcloud"
2425 . "github.com/onsi/ginkgo/v2"
2526 . "github.com/onsi/gomega"
27+ "github.com/stretchr/testify/require"
2628 corev1 "k8s.io/api/core/v1"
2729 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+ "k8s.io/apimachinery/pkg/runtime"
31+ "k8s.io/apimachinery/pkg/types"
32+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2833 "k8s.io/klog/v2"
2934 "k8s.io/utils/ptr"
3035 clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
@@ -33,8 +38,10 @@ import (
3338 v1beta2conditions "sigs.k8s.io/cluster-api/util/deprecated/v1beta1/conditions/v1beta2"
3439 v1beta1patch "sigs.k8s.io/cluster-api/util/deprecated/v1beta1/patch"
3540 "sigs.k8s.io/controller-runtime/pkg/client"
41+ fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
3642 "sigs.k8s.io/controller-runtime/pkg/event"
3743 "sigs.k8s.io/controller-runtime/pkg/predicate"
44+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
3845
3946 infrav1 "github.com/syself/cluster-api-provider-hetzner/api/v1beta1"
4047 hcloudclient "github.com/syself/cluster-api-provider-hetzner/pkg/services/hcloud/client"
@@ -225,6 +232,141 @@ func TestIgnoreInsignificantMachineStatusUpdates(t *testing.T) {
225232 }
226233}
227234
235+ func TestIgnoreInsignificantSecretUpdates (t * testing.T ) {
236+ p := IgnoreInsignificantSecretUpdates (klog .Background ())
237+
238+ makeSecret := func (data map [string ][]byte , rv string ) * corev1.Secret {
239+ return & corev1.Secret {
240+ ObjectMeta : metav1.ObjectMeta {
241+ Name : "hetzner" ,
242+ Namespace : "default" ,
243+ ResourceVersion : rv ,
244+ },
245+ Data : data ,
246+ }
247+ }
248+
249+ testCases := []struct {
250+ name string
251+ oldObj * corev1.Secret
252+ newObj * corev1.Secret
253+ expected bool
254+ }{
255+ {
256+ name : "Data changed" ,
257+ oldObj : makeSecret (map [string ][]byte {"hcloud-token" : []byte ("old" )}, "1" ),
258+ newObj : makeSecret (map [string ][]byte {"hcloud-token" : []byte ("new" )}, "2" ),
259+ expected : true ,
260+ },
261+ {
262+ name : "Only ResourceVersion changed" ,
263+ oldObj : makeSecret (map [string ][]byte {"hcloud-token" : []byte ("same" )}, "1" ),
264+ newObj : makeSecret (map [string ][]byte {"hcloud-token" : []byte ("same" )}, "2" ),
265+ expected : false ,
266+ },
267+ {
268+ name : "Unrelated data key added" ,
269+ oldObj : makeSecret (map [string ][]byte {"hcloud-token" : []byte ("same" )}, "1" ),
270+ newObj : makeSecret (map [string ][]byte {"hcloud-token" : []byte ("same" ), "other" : []byte ("x" )}, "2" ),
271+ expected : true ,
272+ },
273+ }
274+
275+ for _ , tc := range testCases {
276+ t .Run (tc .name , func (t * testing.T ) {
277+ got := p .Update (event.UpdateEvent {ObjectOld : tc .oldObj , ObjectNew : tc .newObj })
278+ require .Equal (t , tc .expected , got )
279+ })
280+ }
281+
282+ require .True (t , p .Create (event.CreateEvent {Object : makeSecret (nil , "1" )}))
283+ require .True (t , p .Delete (event.DeleteEvent {Object : makeSecret (nil , "1" )}))
284+ require .False (t , p .Generic (event.GenericEvent {Object : makeSecret (nil , "1" )}))
285+ }
286+
287+ func TestHetznerSecretToHCloudMachines (t * testing.T ) {
288+ ctx := context .Background ()
289+
290+ testScheme := runtime .NewScheme ()
291+ utilruntime .Must (corev1 .AddToScheme (testScheme ))
292+ utilruntime .Must (infrav1 .AddToScheme (testScheme ))
293+ utilruntime .Must (clusterv1 .AddToScheme (testScheme ))
294+
295+ const (
296+ ns = "default"
297+ secretName = "hetzner"
298+ clusterName = "cluster-a"
299+ )
300+
301+ newCluster := func (name string ) * clusterv1.Cluster {
302+ return & clusterv1.Cluster {
303+ ObjectMeta : metav1.ObjectMeta {Name : name , Namespace : ns , UID : types .UID (name + "-uid" )},
304+ }
305+ }
306+ newHetznerCluster := func (name , clusterOwner , secret string ) * infrav1.HetznerCluster {
307+ return & infrav1.HetznerCluster {
308+ ObjectMeta : metav1.ObjectMeta {
309+ Name : name ,
310+ Namespace : ns ,
311+ OwnerReferences : []metav1.OwnerReference {
312+ {APIVersion : clusterv1 .GroupVersion .String (), Kind : "Cluster" , Name : clusterOwner , UID : types .UID (clusterOwner + "-uid" )},
313+ },
314+ },
315+ Spec : infrav1.HetznerClusterSpec {
316+ HetznerSecret : infrav1.HetznerSecretRef {
317+ Name : secret ,
318+ Key : infrav1.HetznerSecretKeyRef {HCloudToken : "hcloud-token" },
319+ },
320+ },
321+ }
322+ }
323+ newMachine := func (name , clusterOwner , infraName string ) * clusterv1.Machine {
324+ return & clusterv1.Machine {
325+ ObjectMeta : metav1.ObjectMeta {
326+ Name : name ,
327+ Namespace : ns ,
328+ Labels : map [string ]string {clusterv1 .ClusterNameLabel : clusterOwner },
329+ },
330+ Spec : clusterv1.MachineSpec {
331+ ClusterName : clusterOwner ,
332+ InfrastructureRef : clusterv1.ContractVersionedObjectReference {
333+ APIGroup : infrav1 .GroupVersion .Group ,
334+ Kind : "HCloudMachine" ,
335+ Name : infraName ,
336+ },
337+ },
338+ }
339+ }
340+
341+ capiClusterA := newCluster (clusterName )
342+ capiClusterB := newCluster ("cluster-b" )
343+ hcA := newHetznerCluster ("hc-a" , clusterName , secretName )
344+ hcB := newHetznerCluster ("hc-b" , "cluster-b" , secretName )
345+ hcUnrelated := newHetznerCluster ("hc-u" , clusterName , "other-secret" )
346+ hcmA := & infrav1.HCloudMachine {ObjectMeta : metav1.ObjectMeta {Name : "m-a" , Namespace : ns }}
347+ hcmB := & infrav1.HCloudMachine {ObjectMeta : metav1.ObjectMeta {Name : "m-b" , Namespace : ns }}
348+ cmA := newMachine ("cm-a" , clusterName , hcmA .Name )
349+ cmB := newMachine ("cm-b" , "cluster-b" , hcmB .Name )
350+ matchingSecret := & corev1.Secret {ObjectMeta : metav1.ObjectMeta {Name : secretName , Namespace : ns }}
351+ otherSecret := & corev1.Secret {ObjectMeta : metav1.ObjectMeta {Name : "no-ref" , Namespace : ns }}
352+
353+ c := fakeclient .NewClientBuilder ().
354+ WithScheme (testScheme ).
355+ WithObjects (capiClusterA , capiClusterB , hcA , hcB , hcUnrelated , hcmA , hcmB , cmA , cmB ).
356+ Build ()
357+
358+ r := & HCloudMachineReconciler {Client : c }
359+ mapper := r .HetznerSecretToHCloudMachines (ctx )
360+
361+ got := mapper (ctx , matchingSecret )
362+ require .ElementsMatch (t , []reconcile.Request {
363+ {NamespacedName : client.ObjectKey {Namespace : ns , Name : hcmA .Name }},
364+ {NamespacedName : client.ObjectKey {Namespace : ns , Name : hcmB .Name }},
365+ }, got )
366+
367+ require .Empty (t , mapper (ctx , otherSecret ))
368+ }
369+
228370var _ = Describe ("HCloudMachineReconciler" , func () {
229371 var (
230372 capiCluster * clusterv1.Cluster
0 commit comments