@@ -38,12 +38,18 @@ import (
38
38
"k8s.io/apimachinery/pkg/runtime"
39
39
"k8s.io/utils/pointer"
40
40
capiv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
41
+ bsutil "sigs.k8s.io/cluster-api/bootstrap/util"
42
+ expv1 "sigs.k8s.io/cluster-api/exp/api/v1alpha3"
43
+ "sigs.k8s.io/cluster-api/feature"
41
44
"sigs.k8s.io/cluster-api/util"
42
45
"sigs.k8s.io/cluster-api/util/patch"
46
+ "sigs.k8s.io/cluster-api/util/predicates"
43
47
ctrl "sigs.k8s.io/controller-runtime"
44
48
"sigs.k8s.io/controller-runtime/pkg/client"
45
49
"sigs.k8s.io/controller-runtime/pkg/controller"
46
50
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
51
+ "sigs.k8s.io/controller-runtime/pkg/handler"
52
+ "sigs.k8s.io/controller-runtime/pkg/source"
47
53
)
48
54
49
55
const (
@@ -58,9 +64,9 @@ type TalosConfigReconciler struct {
58
64
}
59
65
60
66
type TalosConfigScope struct {
61
- Config * bootstrapv1alpha3.TalosConfig
62
- Machine * capiv1. Machine
63
- Cluster * capiv1.Cluster
67
+ Config * bootstrapv1alpha3.TalosConfig
68
+ ConfigOwner * bsutil. ConfigOwner
69
+ Cluster * capiv1.Cluster
64
70
}
65
71
66
72
type TalosConfigBundle struct {
@@ -80,16 +86,51 @@ type talosConfigContext struct {
80
86
Key string
81
87
}
82
88
83
- func (r * TalosConfigReconciler ) SetupWithManager (mgr ctrl.Manager , options controller.Options ) error {
84
- return ctrl .NewControllerManagedBy (mgr ).
85
- WithOptions (options ).
89
+ func (r * TalosConfigReconciler ) SetupWithManager (ctx context.Context , mgr ctrl.Manager , options controller.Options ) error {
90
+ r .Scheme = mgr .GetScheme ()
91
+
92
+ b := ctrl .NewControllerManagedBy (mgr ).
86
93
For (& bootstrapv1alpha3.TalosConfig {}).
87
- Complete (r )
94
+ WithOptions (options ).
95
+ Watches (
96
+ & source.Kind {Type : & capiv1.Machine {}},
97
+ & handler.EnqueueRequestsFromMapFunc {
98
+ ToRequests : handler .ToRequestsFunc (r .MachineToBootstrapMapFunc ),
99
+ },
100
+ )
101
+
102
+ if feature .Gates .Enabled (feature .MachinePool ) {
103
+ b = b .Watches (
104
+ & source.Kind {Type : & expv1.MachinePool {}},
105
+ & handler.EnqueueRequestsFromMapFunc {
106
+ ToRequests : handler .ToRequestsFunc (r .MachinePoolToBootstrapMapFunc ),
107
+ },
108
+ )
109
+ }
110
+
111
+ c , err := b .Build (r )
112
+ if err != nil {
113
+ return err
114
+ }
115
+
116
+ err = c .Watch (
117
+ & source.Kind {Type : & capiv1.Cluster {}},
118
+ & handler.EnqueueRequestsFromMapFunc {
119
+ ToRequests : handler .ToRequestsFunc (r .ClusterToTalosConfigs ),
120
+ },
121
+ predicates .ClusterUnpausedAndInfrastructureReady (r .Log ),
122
+ )
123
+ if err != nil {
124
+ return err
125
+ }
126
+
127
+ return nil
88
128
}
89
129
90
130
// +kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=talosconfigs,verbs=get;list;watch;create;update;patch;delete
91
131
// +kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=talosconfigs/status,verbs=get;update;patch
92
132
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status;machines;machines/status,verbs=get;list;watch
133
+ // +kubebuilder:rbac:groups=exp.cluster.x-k8s.io,resources=machinepools;machinepools/status,verbs=get;list;watch
93
134
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
94
135
95
136
func (r * TalosConfigReconciler ) Reconcile (req ctrl.Request ) (_ ctrl.Result , rerr error ) {
@@ -100,39 +141,39 @@ func (r *TalosConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, rerr
100
141
101
142
// Lookup the talosconfig config
102
143
config := & bootstrapv1alpha3.TalosConfig {}
103
- if err := r .Get (ctx , req .NamespacedName , config ); err != nil {
144
+ if err := r .Client . Get (ctx , req .NamespacedName , config ); err != nil {
104
145
if apierrors .IsNotFound (err ) {
105
146
return ctrl.Result {}, nil
106
147
}
107
148
log .Error (err , "failed to get config" )
108
149
return ctrl.Result {}, err
109
150
}
110
151
111
- // Look up the Machine that owns this talosconfig if there is one
112
- machine , err := util . GetOwnerMachine (ctx , r .Client , config . ObjectMeta )
152
+ // Look up the resource that owns this talosconfig if there is one
153
+ owner , err := bsutil . GetConfigOwner (ctx , r .Client , config )
113
154
if err != nil {
114
- log .Error (err , "could not get owner machine " )
155
+ log .Error (err , "could not get owner resource " )
115
156
return ctrl.Result {}, err
116
157
}
117
- if machine == nil {
118
- log .Info ("Waiting for Machine Controller to set OwnerRef on the talosconfig" )
158
+ if owner == nil {
159
+ log .Info ("Waiting for OwnerRef on the talosconfig" )
119
160
return ctrl.Result {}, errors .New ("no owner ref" )
120
161
}
121
- log = log .WithName (fmt .Sprintf ("machine -name=%s" , machine . Name ))
162
+ log = log .WithName (fmt .Sprintf ("owner -name=%s" , owner . GetName () ))
122
163
123
164
// Lookup the cluster the machine is associated with
124
- cluster , err := util .GetClusterFromMetadata (ctx , r .Client , machine . ObjectMeta )
165
+ cluster , err := util .GetClusterByName (ctx , r .Client , owner . GetNamespace (), owner . ClusterName () )
125
166
if err != nil {
126
167
log .Error (err , "could not get cluster by machine metadata" )
127
168
return ctrl.Result {}, err
128
169
}
129
170
130
171
// Initialize the patch helper
131
- patchHelper , err := patch .NewHelper (config , r )
172
+ patchHelper , err := patch .NewHelper (config , r . Client )
132
173
if err != nil {
133
174
return ctrl.Result {}, err
134
175
}
135
- // Always attempt to Patch the KubeadmConfig object and status after each reconciliation.
176
+ // Always attempt to Patch the TalosConfig object and status after each reconciliation.
136
177
defer func () {
137
178
if err := patchHelper .Patch (ctx , config ); err != nil {
138
179
log .Error (err , "failed to patch config" )
@@ -163,9 +204,9 @@ func (r *TalosConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, rerr
163
204
}
164
205
165
206
tcScope := & TalosConfigScope {
166
- Config : config ,
167
- Machine : machine ,
168
- Cluster : cluster ,
207
+ Config : config ,
208
+ ConfigOwner : owner ,
209
+ Cluster : cluster ,
169
210
}
170
211
171
212
var retData * TalosConfigBundle
@@ -214,17 +255,31 @@ func (r *TalosConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, rerr
214
255
}
215
256
216
257
// Packet acts a fool if you don't prepend #!talos to the userdata
217
- // so we try to suss out if that's the type of machine getting created.
218
- if machine .Spec .InfrastructureRef .Kind == "PacketMachine" {
219
- retData .BootstrapData = "#!talos\n " + retData .BootstrapData
258
+ // so we try to suss out if that's the type of machine/machinePool getting created.
259
+ if owner .IsMachinePool () {
260
+ mp := & expv1.MachinePool {}
261
+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (owner .Object , mp ); err != nil {
262
+ return ctrl.Result {}, err
263
+ }
264
+ if mp .Spec .Template .Spec .InfrastructureRef .Kind == "PacketMachinePool" {
265
+ retData .BootstrapData = "#!talos\n " + retData .BootstrapData
266
+ }
267
+ } else {
268
+ machine := & capiv1.Machine {}
269
+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (owner .Object , machine ); err != nil {
270
+ return ctrl.Result {}, err
271
+ }
272
+ if machine .Spec .InfrastructureRef .Name == "PacketMachine" {
273
+ retData .BootstrapData = "#!talos\n " + retData .BootstrapData
274
+ }
220
275
}
221
276
222
277
err = r .writeBootstrapData (ctx , tcScope , []byte (retData .BootstrapData ))
223
278
if err != nil {
224
279
return ctrl.Result {}, err
225
280
}
226
281
227
- config .Status .DataSecretName = pointer .StringPtr (tcScope .Machine . Name + "-bootstrap-data" )
282
+ config .Status .DataSecretName = pointer .StringPtr (tcScope .ConfigOwner . GetName () + "-bootstrap-data" )
228
283
config .Status .TalosConfig = retData .TalosConfig
229
284
config .Status .Ready = true
230
285
@@ -303,8 +358,22 @@ func (r *TalosConfigReconciler) genConfigs(ctx context.Context, scope *TalosConf
303
358
// This also handles version being formatted like "vX.Y.Z" instead of without leading 'v'
304
359
// TrimPrefix returns the string unchanged if the prefix isn't present.
305
360
k8sVersion := constants .DefaultKubernetesVersion
306
- if scope .Machine .Spec .Version != nil {
307
- k8sVersion = strings .TrimPrefix (* scope .Machine .Spec .Version , "v" )
361
+ if scope .ConfigOwner .IsMachinePool () {
362
+ mp := & expv1.MachinePool {}
363
+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (scope .ConfigOwner .Object , mp ); err != nil {
364
+ return retBundle , err
365
+ }
366
+ if mp .Spec .Template .Spec .Version != nil {
367
+ k8sVersion = strings .TrimPrefix (* mp .Spec .Template .Spec .Version , "v" )
368
+ }
369
+ } else {
370
+ machine := & capiv1.Machine {}
371
+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (scope .ConfigOwner .Object , machine ); err != nil {
372
+ return retBundle , err
373
+ }
374
+ if machine .Spec .Version != nil {
375
+ k8sVersion = strings .TrimPrefix (* machine .Spec .Version , "v" )
376
+ }
308
377
}
309
378
310
379
clusterDNS := constants .DefaultDNSDomain
@@ -404,3 +473,84 @@ func (r *TalosConfigReconciler) genConfigs(ctx context.Context, scope *TalosConf
404
473
405
474
return retBundle , nil
406
475
}
476
+
477
+ // MachineToBootstrapMapFunc is a handler.ToRequestsFunc to be used to enqueue
478
+ // request for reconciliation of TalosConfig.
479
+ func (r * TalosConfigReconciler ) MachineToBootstrapMapFunc (o handler.MapObject ) []ctrl.Request {
480
+ m , ok := o .Object .(* capiv1.Machine )
481
+ if ! ok {
482
+ panic (fmt .Sprintf ("Expected a Machine but got a %T" , o ))
483
+ }
484
+
485
+ result := []ctrl.Request {}
486
+ if m .Spec .Bootstrap .ConfigRef != nil && m .Spec .Bootstrap .ConfigRef .GroupVersionKind () == bootstrapv1alpha3 .GroupVersion .WithKind ("TalosConfig" ) {
487
+ name := client.ObjectKey {Namespace : m .Namespace , Name : m .Spec .Bootstrap .ConfigRef .Name }
488
+ result = append (result , ctrl.Request {NamespacedName : name })
489
+ }
490
+ return result
491
+ }
492
+
493
+ // MachinePoolToBootstrapMapFunc is a handler.ToRequestsFunc to be used to enqueue
494
+ // request for reconciliation of TalosConfig.
495
+ func (r * TalosConfigReconciler ) MachinePoolToBootstrapMapFunc (o handler.MapObject ) []ctrl.Request {
496
+ m , ok := o .Object .(* expv1.MachinePool )
497
+ if ! ok {
498
+ panic (fmt .Sprintf ("Expected a MachinePool but got a %T" , o ))
499
+ }
500
+
501
+ result := []ctrl.Request {}
502
+ configRef := m .Spec .Template .Spec .Bootstrap .ConfigRef
503
+ if configRef != nil && configRef .GroupVersionKind ().GroupKind () == bootstrapv1alpha3 .GroupVersion .WithKind ("TalosConfig" ).GroupKind () {
504
+ name := client.ObjectKey {Namespace : m .Namespace , Name : configRef .Name }
505
+ result = append (result , ctrl.Request {NamespacedName : name })
506
+ }
507
+ return result
508
+ }
509
+
510
+ // ClusterToTalosConfigs is a handler.ToRequestsFunc to be used to enqeue
511
+ // requests for reconciliation of TalosConfigs.
512
+ func (r * TalosConfigReconciler ) ClusterToTalosConfigs (o handler.MapObject ) []ctrl.Request {
513
+ result := []ctrl.Request {}
514
+
515
+ c , ok := o .Object .(* capiv1.Cluster )
516
+ if ! ok {
517
+ panic (fmt .Sprintf ("Expected a Cluster but got a %T" , o ))
518
+ }
519
+
520
+ selectors := []client.ListOption {
521
+ client .InNamespace (c .Namespace ),
522
+ client.MatchingLabels {
523
+ capiv1 .ClusterLabelName : c .Name ,
524
+ },
525
+ }
526
+
527
+ machineList := & capiv1.MachineList {}
528
+ if err := r .Client .List (context .TODO (), machineList , selectors ... ); err != nil {
529
+ return nil
530
+ }
531
+
532
+ for _ , m := range machineList .Items {
533
+ if m .Spec .Bootstrap .ConfigRef != nil &&
534
+ m .Spec .Bootstrap .ConfigRef .GroupVersionKind ().GroupKind () == bootstrapv1alpha3 .GroupVersion .WithKind ("TalosConfig" ).GroupKind () {
535
+ name := client.ObjectKey {Namespace : m .Namespace , Name : m .Spec .Bootstrap .ConfigRef .Name }
536
+ result = append (result , ctrl.Request {NamespacedName : name })
537
+ }
538
+ }
539
+
540
+ if feature .Gates .Enabled (feature .MachinePool ) {
541
+ machinePoolList := & expv1.MachinePoolList {}
542
+ if err := r .Client .List (context .TODO (), machinePoolList , selectors ... ); err != nil {
543
+ return nil
544
+ }
545
+
546
+ for _ , mp := range machinePoolList .Items {
547
+ if mp .Spec .Template .Spec .Bootstrap .ConfigRef != nil &&
548
+ mp .Spec .Template .Spec .Bootstrap .ConfigRef .GroupVersionKind ().GroupKind () == bootstrapv1alpha3 .GroupVersion .WithKind ("TalosConfig" ).GroupKind () {
549
+ name := client.ObjectKey {Namespace : mp .Namespace , Name : mp .Spec .Template .Spec .Bootstrap .ConfigRef .Name }
550
+ result = append (result , ctrl.Request {NamespacedName : name })
551
+ }
552
+ }
553
+ }
554
+
555
+ return result
556
+ }
0 commit comments